目录

前言

1. 一般信息

2. 安装MySQL

3. 教程

4. MySQL程序概述

5. 数据库管理

6. MySQL中的复制

7. 优化

8. 客户端和实用工具程序

9. 语言结构

10. 字符集支持

11. 列类型

12. 函数和操作符

13. SQL语句语法

14. 插件式存储引擎体系结构

15. 存储引擎和表类型

16. 编写自定义存储引擎

17. MySQL簇

18. 分区

19. MySQL中的空间扩展

20. 存储程序和函数

21. 触发程序

22. 视图

23. INFORMATION_SCHEMA信息

24. 精度数学

25. API和库

26. 连接器

27. 扩展MySQL

A. 问题和常见错误

B. 错误代码和消息

C. 感谢

D. MySQL变更史

E. 移植到其他系统

F. 环境变量

G. MySQL正则表达式

H. MySQL中的限制

I. 特性限制

J. GNU通用公共许可

K. MySQL FLOSS许可例外

索引

附录I:特性限制

在本附录中,介绍了使用诸如子查询或视图等MySQL特性时存在的限制。

I.1. 对存储子程序和触发程序的限制

这里介绍的某些限制适用于所有的存储子程序,即存储程序和存储函数。某些限制仅适用于存储函数而不是存储程序。

对存储函数的的所有限制也适用于触发程序。

注释:如果SQL语句,如SELECT ... INTO语句包含具有相同名称的对列的引用以及声明的局部变量,MySQL会将引用解释为变量的名称。这是一种非标准的行为,优先顺序通常是列名、然后是SQL变量和参数。请参见20.2.9.3节,“SELECT ... INTO语句”

存储子程序不能包含任意SQL语句。在存储子程序中,禁止使用下述语句:

·         CHECK TABLES

·         LOCK TABLES, UNLOCK TABLES

·         LOAD DATA, LOAD TABLE

·         SQL预处理语句(PREPAREEXECUTEDEALLOCATE PREPARE)。隐含意义:不能在存储子程序中使用动态SQL语句(其中,能够以字符串形式构造动态语句,然后执行它们)。从MySQL 5.0.13开始,对于存储程序放宽了该限制,但该限制仍适用于存储函数和触发程序。

·         OPTIMIZE TABLE

对于存储函数(而不是存储程序),禁止下述额外语句:

·         执行显式或隐式提交或回滚操作的语句。

·         返回结果集的语句。包括没有INFO子句的SELECT语句,以及SHOW语句。能够用SELECT … INTO,或使用光标和FETCH语句处理结果集的函数。

·         FLUSH语句。注意,尽管能够在存储程序中使用FLUSH,但不能从存储函数或触发程序调用这类存储程序。

注意,尽管某些限制在正常情况下适用于存储函数和触发程序,不适用于存储程序,如果它们是从存储函数或触发程序中调用的,这些限制也适用于存储程序。

使用存储子程序会导致复制问题。关于这方面的进一步讨论,请参见20.4节,“存储子程序和触发程序的二进制日志功能”

INFORMATION_SCHEMA尚不包含PARAMETERS表,因此,对于需要在运行时获取子程序参数信息的应用程序来说,必须采用相应的规避错误,如解析SHOW CREATE语句的输出。

没有存储子程序调试工具。

存储子程序使用了具体化的光标,而不是固有光标(在服务器端生成结果集并对结果集进行高速缓冲处理,然后在客户端获取结果集时按行返回)。

不能提前处理CALL语句。无论是对服务器端预处理语句还是SQL预处理语句,均成立。

为了防止服务器线程间的交互问题,当客户端发出语句时,服务器将使用可用的、用于语句执行的子程序和触发程序快照。也就是说,服务器将计算出可在语句执行期间使用的存储程序、函数和触发程序的列表,加载它们,然后进入语句执行。这意味着,在语句执行的同时,它不会看到其他线程对子程序所作的变更。

I.2. 对服务器端光标的限制

MySQL 5.0.2开始,通过mysql_stmt_attr_set() C API函数实现了服务器端光标。服务器端光标允许在服务器端生成结果集,但不会将其传输到客户端,除非客户端请求这些行。例如,如果客户端执行了查询,但仅对第1行感兴趣,那么不会传输剩余的行。

光标是只读的,不能使用光标来更新行。

未实施UPDATE WHERE CURRENT OFDELETE WHERE CURRENT OF,这是因为不支持可更新的光标。

光标是不可保持的(提交后不再保持打开)。

光标是不敏感的。

光标是不可滚动的。

光标是未命名的。语句处理程序起着光标ID的作用。

对于每条预处理语句,仅能打开1个光标。如果需要多个光标,必须处理多条语句。

如果在预处理模式下不支持语句,不能在生成结果集的语句上使用光标。包括CHECK TABLESHANDLER READSHOW BINLOG EVENTS语句。

I.3. 对子查询的限制

随后将更正的一致缺陷:如果将NULL值与使用ALLANYSOME的子查询进行比较,而且子查询返回空结果,比较操作将对NULL的非标准结果进行评估,而不是TRUEFALSE

子查询的外部语句可以是SELECTINSERTUPDATEDELETESETDO中的任何一个。

仅部分支持行比较操作:

·         对于expr IN (subquery)expr可以是n-tuple(通过行构造程序语法指定),而且子查询能返回n-tuples个行。

·         对于expr op {ALL|ANY|SOME} (subquery)expr必须是标度值,子查询必须是列子查询,不能返回多列行。

换句话讲,对于返回n-tuples行的子查询,支持:

(val_1, ..., val_n) IN (subquery)

但不支持:

(val_1, ..., val_n) op {ALL|ANY|SOME} (subquery)

支持针对IN的行比较,但不支持针对其他的行比较,原因在于,IN实施是通过将其重新编写为“=”比较和AND操作的序列完成的。该方法不能用于ALLANYSOME

未良好优化行构造程序。下面的两个表达式是等效的,但只有第2个表达式能被优化:

(col1, col2, ...) = (val1, val2, ...)
col1 = val1 AND col2 = val2 AND ...

对于IN的子查询优化不如对“=”的优化那样有效。

对于不良IN性能的一种典型情况是,当子查询返回少量行,但外部查询返回将与子查询结果相比较的大量行。

FROM子句中的子查询不能与子查询有关系。在评估外部查询之前,将对它们进行具体化处理(执行以生成结果集),因此,不能按照外部查询的行对它们进行评估。

一般而言,不能更改表,并从子查询内的相同表进行选择。例如,该限制适用于具有下述形式的语句:

DELETE FROM t WHERE ... (SELECT ... FROM t ...);
UPDATE t ... WHERE col = (SELECT ... FROM t ...);
{INSERT|REPLACE} INTO t (SELECT ... FROM t ...);

例外:如果为FROM子句中更改的表使用子查询,前述禁令将不再适用。例如:

UPDATE t ... WHERE col = (SELECT (SELECT ... FROM t...) AS _t ...);

禁令在此不适用,这是因为FROM中的子查询已被具体化为临时表,因此“t”中的相关行已在满足“t”条件的情况下、在更新时被选中。

与子查询相比,针对联合的优化程序更成熟,因此,在很多情况下,如果将其改写为join(联合),使用子查询的语句能够更有效地执行。

但下述情形例外:IN子查询可被改写SELECT DISTINCT联合。例如:

SELECT col FROM t1 WHERE id_col IN (SELECT id_col2 FROM t2 WHERE condition);

可将该语句改写为:

SELECT DISTINCT col FROM t1, t2 WHERE t1.id_col = t2.id_col AND condition;

但在该情况下,联合需要额外的DISTINCT操作,而且与子查询相比,效率并不高。

可能的未来优化:MySQL不改写针对子查询评估的联合顺序。在某些情况下,如果MySQL将其改写为联合,能够更有效地执行子查询。这样,优化程序就能在更多的执行方案间进行选择。例如,它能决定是否首先读取某一表或其他。

例如:

SELECT a FROM outer_table AS ot
WHERE a IN (SELECT a FROM inner_table AS it WHERE ot.b = it.b);

对于该查询,MySQL总会首先扫描outer_table,如然后针对每一行在inner_table上执行子查询。如果outer_table有很多行而inner_table只有少量行,查询的执行速度或许要慢于本应有的速度。

前述查询可改写为:

SELECT a FROM outer_table AS ot, inner_table AS it
WHERE ot.a = it.a AND ot.b = it.b;

在该情况下,我们能扫描小的表(inner_table)并查询outer_table中的行,如果在“ot.a,ot.b”上有索引,速度会更快。

可能的未来优化:对外部查询的每一行评估关联的子查询。更好的方法是,如果外部行的值与之前的行相比没有变化,不对子查询进行再次评估,而是使用以前的结果。

可能的未来优化:通过将结果具体化到临时表,而且该表不使用索引,对FROM子句中的子查询进行评估。在查询中与其他表进行比较时,尽管可能是有用的,但不允许使用索引。

可能的未来优化:如果FROM子句中的子查询类似于可施加MERGE算法的视图,改写查询并采用MERGE算法,以便能够使用索引。下述语句包含这类子查询:

SELECT * FROM (SELECT * FROM t1 WHERE t1.t1_col) AS _t1, t2 WHERE t2.t2_col;

该语句可被改写为联合,如下所示:

SELECT * FROM t1, t2 WHERE t1.t1_col AND t2.t2_col;

这类改写具有两个优点:

1.    避免使用那些不能使用索引的临时表。在改写的查询中,优化程序可在t1上使用索引。

2.    优化程序在选择不同的执行计划方面具有更大的自由。例如,将查询改写为联合,那么就允许优化程序首先使用t1t2

可能的未来优化:对于没有关联子查询的IN= ANY<> ANY= ALL、以及<> ALL,为结果使用内存中哈希处理,或对较大的结果使用具有索引的临时表。例如:

SELECT a FROM big_table AS bt
WHERE non_key_field IN (SELECT non_key_field FROM table WHERE condition)

在该情况下,可创建临时表:

CREATE TABLE t (key (non_key_field))
(SELECT non_key_field FROM table WHERE condition)

然后,对big_table中的每一行,根据bt.non_key_field,在“t”中进行键查找。

I.4. 对视图的限制

视图处理功能概念未优化:

·         不能在视图上创建索引。

·         对于使用MERGE算法处理的视图,可以使用索引。但是,对于使用临时表算法处理的视图,不能在其基表上利用索引提供的优点(尽管能够在临时表的生成过程中使用索引)。

在视图的FROM子句中不能使用子查询。未来该限制将被放宽。

存在一个一般原则,不能更改某一表并在子查询的相同表内进行选择。请参见I.3节,“对子查询的限制”

如果从表选择了视图并接着从视图进行了选择,同样的原理也适用,如果在子查询中从表选择了视图并使用MERGE算法评估了视图,也同样。例如:

CREATE VIEW v1 AS
SELECT * FROM t2 WHERE EXISTS (SELECT 1 FROM t1 WHERE t1.a = t2.a);
 
UPDATE t1, v2 SET t1.a = 1 WHERE t1.b = v2.b;

如果视图是使用临时表评估的,可从视图子查询中的表进行选择,并仍能更改外部查询中的表。在该情况下,视图将被具体化,因此,你实际上不能从子查询的表中进行选择并“同时”更改它(这是你打算强制MySQL使用临时表算法的另一原因,其方法是在视图定义中指定ALGORITHM = TEMPTABLE关键字)。

可以使用DROP TABLEALTER TABLE来舍弃或更改视图定义中使用的表(它会是视图失效),而且舍弃或更改操作不会导致告警。但在以后使用视图时会出错。

视图定义是通过特定语句“冻结”的:

·         如果PREPARE预处理的语句引用了视图,以后每次执行语句时看到的视图内容与预处理视图时的内容相同。即使在语句预处理完成之后、在执行语句之前更改了视图定义,情况也同样。例如:

·                CREATE VIEW v AS SELECT 1;
·                PREPARE s FROM 'SELECT * FROM v';
·                ALTER VIEW v AS SELECT 2;
·                EXECUTE s;

EXECUTE语句返回的结果是1,而不是2

·         如果存储子程序中的语句引用了视图,语句所见到的视图内容与首次执行语句时的相同。这意味着,如果语句是以循环方式执行的,进一步的语句迭代见到的视图内容是相同的,即使在循环过程中更改了视图定义也同样。例如:

·                CREATE VIEW v AS SELECT 1;
·                delimiter //
·                CREATE PROCEDURE p ()
·                BEGIN
·                  DECLARE i INT DEFAULT 0;
·                  WHILE i < 5 DO
·                    SELECT * FROM v;
·                    SET i = i + 1;
·                    ALTER VIEW v AS SELECT 2;
·                  END WHILE;
·                END;
·                //
·                delimiter ;
·                CALL p();

如果调用了程序p(),每次通过循环时SELECT返回1,即使在循环内更改了视图定义也同样。

关于视图的可更新性,对于视图,其总体目标是,如果任何视图从理论上讲是可更新的,在实际上也应是可更新的。这包括在其定义中有UNION的视图。目前,并非所有理论上可更新的视图均能被更新。最初的视图实施有意采用该方式,为的是尽快地在MySQL中获得有用的可更新视图。很多理论上可更新的视图现已能更新,但限制依然存在:

·         其子查询位于WHERE子句之外任何位置的可更新视图。对于某些其子查询位于SELECT列表中的视图,也是可更新的。

·         不能使用UPDATE来更新定义为Join的视图的1个以上的基表。

·         不能使用DELETE来更新定义为Join的视图。

I.5. 对XA事务的限制

XA事务支持限于InnoDB存储引擎。

MySQL XA实施是针对外部XA的,其中,MySQL服务器作为资源管理器,而客户端程序作为事务管理器。未实施“内部XA”。这样,就允许MySQL服务器内的单独存储引擎作为RM(资源管理器),而服务器本身作为TM(事务管理器)。处理包含1个以上存储引擎的XA事务时,需要内部XA。内部XA的实施是不完整的,这是因为,它要求存储引擎在表处理程序层面上支持两阶段提交,目前仅对InnoDB实现了该特性。

对于XA START,不支持JOINRESUME子句。

对于XA END,不支持SUSPEND [FOR MIGRATE]子句。

在全局事务内,对于每个XA事务,xid值的bqual部分应是不同的,该要求是对当前MySQL XA实施的限制。它不是XA规范的组成部分。

如果XA事务达到PREPARED状态而且MySQL服务器宕机,当服务器重启后,能够继续处理事务。就像原本应当的那样。但是,如果客户端连接中止而服务器继续运行,服务器将回滚任何未完成的XA事务,即使该事务已达到PREPARED状态也同样。它应能提交或回滚PREPARED XA事务,但在不更改二进制日志机制的情况下不能这样。


这是MySQL参考手册的翻译版本,关于MySQL参考手册,请访问dev.mysql.com。原始参考手册为英文版,与英文版参考手册相比,本翻译版可能不是最新的。


This file is decompiled by an unregistered version of ChmDecompiler.
Regsitered version does not show this message.
You can download ChmDecompiler at : http://www.etextwizard.com/