Mysql 8.0 第13章 SQL语句的语法 (第2节)

内容太多,按小节开。上一节见 第 13.1节
翻译居多,译者附加了自己的例子,感觉的翻译不准的地方,已经附加了原文!

13.2 数据操作语句(DML)

13.2.1 CALL语法

CALL sp_name([parameter[,...]])
CALL sp_name[()]

CALL语句调用先前使用CREATE PROCEDURE定义的存储过程。

不带参数的存储过程有两种调用方式CALL p()或者CALL p(他们是等价的)。

CALL可以使用 OUT或 INOUT参数。当过程返回时,客户端程序还可以获取在例程中执行的最终语句受影响的行数:在SQL级别,调用 ROW_COUNT()函数; 从C API方面,可以调用 mysql_affected_rows()函数。

有关未处理条件对过程参数的影响的信息,请参见 第13.6.7.8节“条件处理和OUT或INOUT参数”

要使用OUT或 INOUT参数从过程中获取值 ,请通过用户变量传递参数,然后在过程返回后检查变量的值。(如果要调用从另一个存储过程或函数内的程序,也可以通过常规参数或局部例程变量作为IN或INOUT 参数)。对于一个INOUT参数,它传递给过程之前初始化它的值。以下过程具有OUT参数,此过程在INOUT参数上设置当前服务器版本的 ,还有一个递增的值:

CREATE PROCEDURE p (OUT ver_param VARCHAR(25), INOUT incr_param INT)
BEGIN
  # Set value of OUT parameter
  SELECT VERSION() INTO ver_param;
  # Increment value of INOUT parameter
  SET incr_param = incr_param + 1;
END;

在调用过程之前,初始化要作为INOUT参数传递的变量。调用该过程后,将设置或修改两个变量的值:

mysql> SET @increment = 10;
mysql> CALL p(@version, @increment);
mysql> SELECT @version, @increment;
+--------------------+------------+
| @version           | @increment |
+--------------------+------------+
| 8.0.3-rc-debug-log |         11 |
+--------------------+------------+

在使用了PREPARE和 EXECUTE的CALL预准备语句中,占位符可用于IN,OUT和 INOUT参数。这些类型的参数可以使用如下:

mysql> SET @increment = 10;
mysql> PREPARE s FROM 'CALL p(?, ?)';
mysql> EXECUTE s USING @version, @increment;
mysql> SELECT @version, @increment;
+--------------------+------------+
| @version           | @increment |
+--------------------+------------+
| 8.0.3-rc-debug-log |         11 |
+--------------------+------------+

要编写使用CALLSQL语句执行生成结果集的存储过程的C程序, 必须启用CLIENT_MULTI_RESULTS。这是因为每个CALL返回结果以指示调用状态,以及可能由过程中执行的语句返回的任何结果集。如果CALL用于执行包含预准备语句的任何存储过程,必须启用CLIENT_MULTI_RESULTS。无论何时加载这样的过程都无法确定这些语句是否会产生结果集,因此有必要假设它们会产生结果集。

调用mysql_real_connect()时会默认启用CLIENT_MULTI_RESULTS,可以通过传递CLIENT_MULTI_RESULTS 标志本身显式启用,也可以通过启用CLIENT_MULTI_STATEMENTS(它会隐式启用 CLIENT_MULTI_RESULTS)。

要处理mysql_query()mysql_real_query()执行的CALL 语句的结果,请使用循环mysql_next_result()来确定是否有更多结果。有关示例,请参见 第28.7.19节“C API多语句执行支持”

C程序可以使用prepared-statement接口来执行 CALL语句,访问 OUT和INOUT参数。这是通过mysql_stmt_next_result()循环处理CALL语句的结果来完成的。有关示例,请参见 第28.7.21节“C API准备的CALL语句支持”。提供MySQL接口的语言可以使用预准备 CALL语句直接检索OUT和INOUT 过程参数。

检测到存储程序引用的对象的元数据更改,并在下次执行程序时自动重新分析受影响的语句。有关更多信息,请参见 第8.10.3节“准备语句和存储程序的缓存”

13.2.2 DELETE语法

DELETE是一个从表中删除行的DML语句。

一个DELETE语句可以用WITH子句开始,用来定义DELETE内可以访问的公共表达式 。请参见第13.2.13节“WITH语法(公用表表达式)”

13.2.2.1 单表语法

DELETE [LOW_PRIORITY] [QUICK] [IGNORE] FROM tbl_name
    [PARTITION (partition_name [, partition_name] ...)]
    [WHERE where_condition]
    [ORDER BY ...]
    [LIMIT row_count]

DELETE语句从tbl_name中删除行并返回已删除行的数量。要检查已删除行的数量,请调用 第12.15节“信息函数”中所述的ROW_COUNT()。

主要部分
WHERE子句中的参数标识要删除的行。如果没有WHERE子句,则删除所有行。

where_condition是一个表达式,对于要删除的每一行,计算结果为true。它的规定如 第13.2.10节“SELECT语法”中所述

如果指定了ORDER BY子句,则按指定的顺序删除行。 LIMIT子句限制了可以删除的行数。这些子句适用于单表删除,但不适用于多表删除。

13.2.2.2 多表语法

DELETE [LOW_PRIORITY] [QUICK] [IGNORE]
    tbl_name[.*] [, tbl_name[.*]] ...
    FROM table_references
    [WHERE where_condition]

DELETE [LOW_PRIORITY] [QUICK] [IGNORE]
    FROM tbl_name[.*] [, tbl_name[.*]] ...
    USING table_references
    [WHERE where_condition]

13.2.2.3 相关介绍

权限
您需要表上的DELETE权限才能从中删除行。您需要对只读取的列的SELECT权限,例如在 WHERE子句中指定的列。

性能
当您不需要知道已删除行的数量时,TRUNCATE TABLE语句比 没有 WHERE子句的DELETE语句更快。不同的是TRUNCATE TABLE不能在事务中使用或者如果您对表有锁定。请参见 第13.1.37节“TRUNCATE TABLE语法”第13.3.6节“LOCK TABLES和UNLOCK TABLES语法”

删除操作的速度也可能受 第8.2.5.3节“优化DELETE语句”中讨论的因素的影响。

为确保给定DELETE 语句不占用太多时间,IMIT row_count子句指定要删除的最大行数。如果要删除的行数大于限制,请重复DELETE语句,直到受影响的行数小于LIMIT值。

子查询
在一个子查询中,无法对一个表既DELETE又SELECT
译者实例:

mysql> delete from t_data where id > 5051638 and id in (select id from t_data where id> 5051637);
Error Code: 1093. You can't specify target table 't_data' for update in FROM clause

分区表
DELETE支持使用PARTITION选项显式分区选择,该选项获取一个或多个分区或子分区(或两者)的逗号分隔名称列表,从中选择要删除的行。未包含在列表中的分区将被忽略。给定一个表t带有一个分区表 p0,执行该语句DELETE FROM t PARTITION (p0)对表的执行效果与执行ALTER TABLE t TRUNCATE PARTITION (p0)相同; 在这两种情况下,分区p0中的所有行都将被删除。

PARTITION可以与WHERE条件一起使用 ,在这种情况下,仅对列出的分区中的行测试条件。例如, DELETE FROM t PARTITION (p0) WHERE c < 5 仅从p0分区中删除条件c < 5为true的行。

该PARTITION选项也可用于多表DELETE语句。您可以在FROM选项中指定的每个表中使用最多一个此类 选项。

有关更多信息和示例,请参见 第23.5节“分区选择”

自动增长列
如果删除包含列的最大值AUTO_INCREMENT的行 ,则不会为MyISAM或InnoDB表重用该值。如果在autocommit模式(默认启用)下使用DELETE FROM tbl_name删除表中的所有行(没有WHERE子句) ,则除了MyISAM和InnoDB之外的所有存储引擎都会重新开始 。InnoDB 表的这种行为有一些例外,如 第15.6.1.4节“InnoDB中的AUTO_INCREMENT处理”中所述。

对于MyISAM表,您可以在多列索引中指定一个AUTO_INCREMENT二级列。在这种情况下,即使对于MyISAM 表,也会重复使用从序列顶部删除的值。请参见第3.6.9节“使用AUTO_INCREMENT”

修饰符
DELETE语句支持以下修饰符:

如果指定LOW_PRIORITY,则服务器会延迟执行DELETE,直到没有其他客户端从表中读取。这会影响只使用表级锁的存储引擎(例如MyISAM,MEMORY和MERGE)。

对于MyISAM表,如果使用 QUICK修饰符,则存储引擎在删除期间不会合并索引叶,这可能会加速某些类型的删除操作。

IGNORE修饰符导致MySQL删除行的过程中忽略的错误。(解析阶段遇到的错误以常规方式处理。)由于使用IGNORE,被忽略的错误 将作为警告返回。有关更多信息,请参阅 IGNORE关键字和严格SQL模式的比较

删除顺序
如果DELETE语句包含 ORDER BY子句,则按照子句指定的顺序删除行。与结合LIMIT使用会很有用。例如,以下语句查找与WHERE子句匹配的行,对其进行timestamp_column排序,并删除第一个(最旧的):

DELETE FROM somelog WHERE user = 'jcole'
ORDER BY timestamp_column LIMIT 1;

ORDER BY 还有助于删除所需的顺序中的行,以避免参照完整性违规。

InnoDB表
如果要从大表中删除许多行,则可能会超出InnoDB表的锁定表大小。为了避免这个问题,或者只是为了最小化表保持锁定的时间,以下策略(根本不使用 DELETE)可能会有所帮助:

  1. 选择不要删除的行到与原始表具有相同结构的空表中:
INSERT INTO t_copy SELECT * FROM t WHERE ... ;
  1. 使用RENAME TABLE以原子移动原始表的方式进行,并重新命名拷贝表为原来表的名称:
RENAME TABLE t TO t_old, t_copy TO t;
  1. 删除原始表:
DROP TABLE t_old;

没有其他会话可以访问在RENAME TABLE执行时所涉及的表 ,因此重命名操作不受并发问题的影响。请参见 第13.1.36节“RENAME TABLE语法”

MyISAM表

多表删除
您可以在DELETE语句中指定多个表,以 根据WHERE子句中的条件从一个或多个表中删除行 。您不能在多表删除中使用ORDER BY或LIMIT。table_references子句列出了连接中涉及的表,如 第13.2.10.2节“JOIN语法”中所述

对于第一个多表语法,仅删除FROM子句前列出的表中的匹配行。对于第二个多表语法,仅删除FROM子句(在USING子句之前)中列出的表中的匹配行。结果是您可以同时从多个表中删除行,并具有仅用于搜索的其他表:

DELETE t1, t2 FROM t1 INNER JOIN t2 INNER JOIN t3
WHERE t1.id=t2.id AND t2.id=t3.id;

要么:

DELETE FROM t1, t2 USING t1 INNER JOIN t2 INNER JOIN t3
WHERE t1.id=t2.id AND t2.id=t3.id;

这些语句查找删除行的时候使用所有三个表,但只从t1和t2中删除匹配行 。

前面的示例使用INNER JOIN,但多表DELETE语句可以使用SELECT语句中允许的其他类型的连接 ,例如LEFT JOIN。例如,要删除t1中存在而 t2中不存在的行,请使用LEFT JOIN:

DELETE t1 FROM t1 LEFT JOIN t2 ON t1.id=t2.id WHERE t2.id IS NULL;

语法允许在每个 tbl_name语句之后使用.*,这是为了与Access兼容 。

如果使用多表DELETE语句涉及InnoDB具有外键约束的表的时候,则MySQL优化器可能会按照与其父/子关系不同的顺序处理表。在这种情况下,语句失败并回滚。相反,您应该从单个表中删除并依赖于 InnoDB提供的ON DELETE功能,以便相应地修改其他表。

注意
如果声明表的别名,则在引用表时必须使用别名:

DELETE t1 FROM test AS t1, test2 WHERE ...

多表DELETE中的表别名 只应在table_references语句的部分声明。在其他地方,允许别名引用但不允许别名声明。

正确:

DELETE a1, a2 FROM t1 AS a1 INNER JOIN t2 AS a2
WHERE a1.id=a2.id;

DELETE FROM a1, a2 USING t1 AS a1 INNER JOIN t2 AS a2
WHERE a1.id=a2.id;

不正确:

DELETE t1 AS a1, t2 AS a2 FROM t1 INNER JOIN t2
WHERE a1.id=a2.id;

DELETE FROM t1 AS a1, t2 AS a2 USING t1 INNER JOIN t2
WHERE a1.id=a2.id;

13.2.3 DO语法

DO expr [, expr] ...

DO执行表达式但不返回任何结果。在大多数方面,它 DO是SELECT expr, ...的简写,但有一个优点,当你不关心结果时它会稍微快一些。

DO主要用于具有副作用的函数,例如 RELEASE_LOCK()

示例:此SELECT语句暂停,但也会生成结果集:

mysql> SELECT SLEEP(5);
+----------+
| SLEEP(5) |
+----------+
|        0 |
+----------+
1 row in set (5.02 sec)

使用DO,暂停而不产生结果集:

mysql> DO SLEEP(5);
Query OK, 0 rows affected (4.99 sec)

这可能很有用,例如在存储函数或触发器中,它禁止生成结果集的语句。

DO只执行表达式。它不能用于所有SELECT可以使用的情况。例如,DO id FROM t1它是无效的,因为它引用了一个表。

13.2.10 SELECT语法

SELECT
    [ALL | DISTINCT | DISTINCTROW ]
      [HIGH_PRIORITY]
      [STRAIGHT_JOIN]
      [SQL_SMALL_RESULT] [SQL_BIG_RESULT] [SQL_BUFFER_RESULT]
      SQL_NO_CACHE [SQL_CALC_FOUND_ROWS]
    select_expr [, select_expr ...]
    [FROM table_references
      [PARTITION partition_list]
    [WHERE where_condition]
    [GROUP BY {col_name | expr | position}, ... [WITH ROLLUP]]
    [HAVING where_condition]
    [WINDOW window_name AS (window_spec)
        [, window_name AS (window_spec)] ...]
    [ORDER BY {col_name | expr | position}
      [ASC | DESC], ... [WITH ROLLUP]]
    [LIMIT {[offset,] row_count | row_count OFFSET offset}]
    [INTO OUTFILE 'file_name'
        [CHARACTER SET charset_name]
        export_options
      | INTO DUMPFILE 'file_name'
      | INTO var_name [, var_name]]
    [FOR {UPDATE | SHARE} [OF tbl_name [, tbl_name] ...] [NOWAIT | SKIP LOCKED] 
      | LOCK IN SHARE MODE]]

SELECT用于检索从一个或多个表中选择的行,并且可以包括 UNION语句和子查询。请参见第13.2.10.3节“UNION语法”第13.2.11节“子查询语法”。一个 SELECT语句可以用WITH子句开始 来定义SELECT内可以访问的公共表的表达式 。请参见第13.2.13节“WITH语法(公用表表达式)”

最常用的SELECT 子部分是:

  • 每个select_expr都表示要一个检索的列。必须至少有一个 select_expr。

  • table_references表示要从中检索行的一个或多个表。其语法在 第13.2.10.2节“JOIN语法”中描述。

  • SELECT支持使用PARTITION选项进行显式地分区选择,可以是分区列表或子分区(或两者)跟随在table_reference(参见 第13.2.10.2节“JOIN语法”)后面。在这种情况下,仅从列出的分区中选择行,并忽略表的任何其他分区。有关更多信息和示例,请参见 第23.5节“分区选择”

SELECT ... PARTITION从使用MyISAM存储引擎的表中执行表级锁(以及分区锁),仅锁定PARTITION选项指定的分区或子分区 。

有关更多信息,请参阅 分区和锁定

  • 如果给出WHERE子句,则表示行必须满足要选择的条件。 where_condition是一个表达式,对于要选择的每一行,计算结果为true。如果没有WHERE子句,该语句将选择所有行 。

在WHERE表达式中,您可以使用MySQL支持的任何函数和运算符,但聚合(汇总)函数除外。请参见 第9.5节“表达式”第12章“ 函数和运算符”

SELECT 也可用于检索计算的行而不引用任何表。

例如:

mysql> SELECT 1 + 1;
        -> 2

在没有引用表的情况下, 您可以指定DUAL为虚拟表名:

mysql> SELECT 1 + 1 FROM DUAL;
        -> 2

DUAL纯粹是为了方便那些要求所有SELECT 语句应该具有FROM以及可能的其他子句的人。FROM DUAL可以忽略。

通常,使用的子句必须完全按照语法描述中显示的顺序给出。例如,一个 HAVING子句必须在任何 GROUP BY子句之后和任何ORDER BY子句之前。例外情况是INTO子句可以如语法描述中所示出现,也可以紧接在select_expr列表后面出现 。有关更多信息INTO,请参见 第13.2.10.1节“SELECT … INTO语法”

select_expr列表包括指示要检索哪些列的选择列表。可以指定列或表达式或可以使用*

  • *可用作选择从所有表中所有列的简写:
SELECT * FROM t1 INNER JOIN t2 ...
  • tbl_name.* 从指定的表中选择所有列:
SELECT t1.*, t2.* FROM t1 INNER JOIN t2 ...
  • *和select的定义列表中的其他术语一起使用可能会产生解析错误。要避免此问题,请使用tbl_name.*
SELECT AVG(score), t1.* FROM t1 ...

以下列表提供了有关其他SELECT子句的其他信息 :

  • select_expr可以使用别名,形式为AS alias_name。别名用作表达式的列名,并且可以在GROUP BY,ORDER BY,HAVING中被使用 。
    例如:
SELECT CONCAT(last_name,', ',first_name) AS full_name
  FROM mytable ORDER BY full_name;

AS可以不写,前面的例子可以这样编的:

SELECT CONCAT(last_name,', ',first_name) full_name
  FROM mytable ORDER BY full_name;

不允许在WHERE子句中引用列别名 ,因为在WHERE 执行子句时可能尚未确定列值。请参见 第B.6.4.4节“列别名的问题”

  • FROM table_references子句指示要从中检索行的一个或多个表。如果您为多个表命名,则表示您正在执行连接。有关连接语法的信息,请参见第13.2.10.2节“JOIN语法”。对于指定的每个表,您可以选择指定别名。
tbl_name [[AS] alias] [index_hint]

index_hint的使用为优化器提供了有关如何在查询处理期间选择索引的信息。有关指定这些提示的语法的说明,请参见 第8.9.4节“索引提示”。

  • 另一种方法,您可以使用SET max_seeks_for_key=value 强制MySQL优先进行key扫描而不是表扫描。请参见 第5.1.8节“服务器系统变量”

  • 您可以将默认数据库中的表称为 tbl_name或 db_name.tbl_name ,同样地列名称也可以加表和数据库名前缀。您无需为一个引用指定这些前缀,除非引用不明确。有关需要更明确的列引用形式的歧义的示例,请参见第9.2.1节“标识符限定符”

  • 表的引用可以使用别名

SELECT t1.name, t2.salary FROM employee AS t1, info AS t2
  WHERE t1.name = t2.name;

SELECT t1.name, t2.salary FROM employee t1, info t2
  WHERE t1.name = t2.name;
  • 用于输出显示的列可以在 ORDER BYGROUP BY子句中再次使用,使用方式可以是列名,列别名或列位置。列位置(不推荐使用列位置,因为已从SQL标准中删除了语法)是整数,以1开头:
SELECT college, region, seed FROM tournament
  ORDER BY region, seed;

SELECT college, region AS r, seed AS s FROM tournament
  ORDER BY r, s;

SELECT college, region, seed FROM tournament
  ORDER BY 2, 3;

默认为升序(ASC),降序使用DESC

如果ORDER BY在子查询中发生并且也在外部查询中应用,则最外层 ORDER BY优先。例如,以下语句的结果按a的降序排序:

(SELECT ... ORDER BY a) ORDER BY a DESC;

在MySQL 8.0.13之前,MySQL支持非标准语法扩展,允许GROUP BY的列指定排序顺序。MySQL 8.0.12及更高版本支持 ORDER BY中分组功能,因此不再需要使用此扩展。(Bug#86312,Bug#26073525)这也意味着您这样使用:

SELECT a, b, COUNT(c) AS t FROM test_table GROUP BY a,b ORDER BY a,t DESC;

从MySQL 8.0.13开始,不允许为GROUP BY中的列指定排序顺序

  • 当您使用 ORDER BY 或 GROUP BY 对SELECT中的列进行排序时,服务器使用max_sort_length系统变量(默认1024)指示的初始字节数对值进行排序 。

  • MySQL扩展了使用GROUP BY功能,以允许GROUP BY子句中可以出现SELECT部分没出现的字段(译者注:如下面例子所示)。如果你没有期望的结果,请阅读 第12.20,“集合(GROUP BY)功能”

mysql> select cpm,cjd from t1 group by id;

以前,不允许ORDER BY在具有WITH ROLLUP修饰符的查询中使用它。从MySQL 8.0.12开始,此限制被取消。请参见 第12.20.2节“GROUP BY Modifiers”。

  • HAVING部分几乎在最后位置应用,没有优化(LIMIT在HAVING之后使用 )。

SQL标准要求HAVING必须仅引用GROUP BY子句或聚合函数中使用的列。但是,MySQL支持对此行为的扩展,并允许 HAVING引用SELECT列表中的列和子查询以外的列。

如果HAVING子句引用不明确的列,则会发出警告。在以下语句中,col2它是不明确的,因为它既用作别名又用作列名:

SELECT COUNT(col1) AS col2 FROM t GROUP BY col2 HAVING col2 = 2;

优先考虑标准SQL行为,出现上例情况,则会优先选择GROUP BY中的列。

  • WHERE子句中的项不要写在HAVING中。例如,不要写下面的内容:
SELECT col_name FROM tbl_name HAVING col_name > 0;

写这个:

SELECT col_name FROM tbl_name WHERE col_name > 0;
  • HAVING子句可以引用聚合函数,WHERE子句不能
SELECT user, MAX(salary) FROM users
  GROUP BY user HAVING MAX(salary) > 10;

(这在一些旧版本的MySQL中不起作用。)

MySQL允许重复的列名。也就是说,可以有多个select_expr名称相同的名称。这是标准SQL的扩展。因为MySQL也允许GROUP BY和HAVING引用 select_expr值,这可能会导致歧义:

SELECT 12 AS a, a FROM t GROUP BY a;
  • WINDOW子句(如果存在)定义了可由窗口函数引用的命名窗口。有关详细信息,请参见第12.21.4节“命名Windows”

  • MySQL先搜索select_expr中的列确定 ORDER BY子句中的列名或别名,然后再从FROM子句中搜索 。对于GROUP BY或者HAVING 子句,它先从FROM子句搜索,再从select_expr 中搜索。(对于GROUP BY和 HAVING,这与MySQL 5.0之前使用相同ORDER BY规则的行为不同。)

  • LIMIT子句可用于约束SELECT语句返回的行数 。 LIMIT取一个或两个数字参数,这些参数必须都是非负整数常量,但有以下例外:

  • 在预准备语句中,LIMIT 可以使用? 占位符标记指定参数。

  • 在存储的程序中,LIMIT 可以使用整数值例程参数或局部变量指定参数。

第一个参数指定从第几条开始(默认0),第二个参数指定要返回的最大行数:

SELECT * FROM tbl LIMIT 5,10;  # Retrieve rows 6-15

要从特定偏移量检索所有行直到结果集的末尾,可以使用一些大数字作为第二个参数。此语句检索从第96行到最后一行的所有行:

SELECT * FROM tbl LIMIT 95,18446744073709551615;

仅指定一个参数,表名从头取取多少条记录:

SELECT * FROM tbl LIMIT 5;     # Retrieve first 5 rows

相当于:LIMIT row_count = LIMIT 0, row_count

对于预准备语句,您可以使用占位符,以下语句将返回表中的第二行到第六行tbl:

SET @skip=1; SET @numrows=5;
PREPARE STMT FROM 'SELECT * FROM tbl LIMIT ?, ?';
EXECUTE STMT USING @skip, @numrows;

为了与PostgreSQL兼容,MySQL也支持LIMIT row_count OFFSET offset语法。

如果LIMIT在子查询中发生并且也在外部查询中应用,则最外层 LIMIT优先。例如,以下语句产生两行,而不是一行:

(SELECT ... LIMIT 1) LIMIT 2;
  • SELECT ... INTO形式的SELECT 使查询结果能够写入文件或存储在变量中。有关更多信息,请参见 第13.2.10.1节“SELECT … INTO语法”

  • 如果存储引擎使用页锁或行锁,你使用了FOR UPDATE,则查询检查的行将被写入锁定,直到当前事务结束。

某些情况,不能将FOR UPDATE用作SELECT声明中的 一部分,例如CREATE TABLE new_table SELECT ... FROM old_table ... 。(如果您尝试这样做,则该语句将被拒绝,并且错报错Can't update table 'old_table' while 'new_table' is being created

FOR SHARELOCK IN SHARE MODE设置共享锁,允许其他事务读取已检查的行,但不允许更新或删除它们。 FOR SHARE和LOCK IN SHARE MODE是等价的。然而FOR SHARE,像FOR UPDATE,支持 NOWAIT,SKIP LOCKED,OF tbl_name 选项。FOR SHARE是LOCK IN SHARE MODE的替代品 ,但后者仍可用于向后兼容。

NOWAIT导致一个FOR UPDATE或FOR SHARE查询立即执行,如果由于另一个事务持有的锁而无法获得行锁,则返回错误。

SKIP LOCKED导致FOR UPDATE或FOR SHARE查询立即执行,排除结果集中由另一个事务锁定的行。

NOWAIT和SKIP LOCKED 选项对于基于语句的复制是不安全的。

注意
跳过锁定行的查询会返回数据的不一致视图。SKIP LOCKED因此不适合一般交易工作。但是,当多个会话访问同一个类似队列的表时,它可用于避免锁争用。↑

OF tbl_name对命名表 应用FOR UPDATE和FOR SHARE查询。例如:

SELECT * FROM t1, t2 FOR SHARE OF t1 FOR UPDATE OF t2;

在SELECT关键字之后,您可以使用许多影响语句操作的修饰符。HIGH_PRIORITYSTRAIGHT_JOIN,以及开头的修饰符 SQL_是标准SQL的MySQL扩展。

  • ALLDISTINCT 修饰符指定重复行是否应该返回。 ALL(默认值)指定应返回所有匹配的行,包括重复行。 DISTINCT指定从结果集中删除重复的行。不能同时指定。DISTINCTROW是DISTINCT。
    的同义词
    在MySQL 8.0.12及更高版本中,DISTINCT可以与也使用WITH ROLLUP的查询一起使用。(Bug#87450,Bug#26640100)

*HIGH_PRIORITY 对SELECT比更新表的语句提供更高的优先级。您应该仅将此用于非常快速且必须立即执行的查询。SELECT HIGH_PRIORITY在表被锁定以进行读取时发出的 查询即使存在等待表空闲的更新语句也会运行。这会影响只使用表级锁的存储引擎(例如MyISAM,MEMORY和MERGE)。

HIGH_PRIORITY不能与SELECT作为 UNION的一部分一起使用。

  • STRAIGHT_JOIN强制优化器按照FROM子句中列出的顺序连接表 。如果优化程序以非最佳顺序连接表,则可以使用此方法加速查询。 STRAIGHT_JOIN也可以在 table_references列表中使用。请参见 第13.2.10.2节“JOIN语法”

猜你喜欢

转载自blog.csdn.net/lengfengyuyu/article/details/84886646