MySQL对子查询的优化

子查询语法

在一个查询语句A里的某个位置也可以有另一个查询语句B,这个出现在A
语句的某个位置中的查询B就被称为子查询,A也被称之为外层查询。子查询可
以在一个外层查询的各种位置出现,

子查询出现在SELECT子句中

也就是我们平时说的查询列表中,比如这样:

SELECT (SELECT m1 FROM e1 LIMIT 1);

其中的(SELECT m1 FROM e1 LIMIT 1)就是子查询。

子查询出现在FROM子句中

比如:

SELECT m, n FROM (SELECT m2 + 1 AS m, n2 AS n FROM e2 WHERE m2 > 2) AS
 t;

这个例子中的子查询是:(SELECT m2 + 1 AS m, n2 AS n FROM e2 WHERE m2 >
2),这里可以把子查询的查询结果当作是一个表,子查询后边的AS t表明这个子
查询的结果就相当于一个名称为t的表,这个名叫t的表的列就是子查询结果中
的列,比如例子中表t就有两个列:m列和n列。这个放在FROM子句中的子查
询本质上相当于一个表,但又和我们平常使用的表有点儿不一样,MySQL 把这种
由子查询结果集组成的表称之为派生表。

子查询出现在WHERE或ON子句中

把子查询放在外层查询的WHERE子句或者ON子句中可能是我们最常用的
一种使用子查询的方式了,比如这样:

SELECT * FROM e1 WHERE m1 IN (SELECT m2 FROM e2);

这个查询表明我们想要将(SELECT m2 FROM e2)这个子查询的结果作为外层
查询的IN语句参数,整个查询语句的意思就是我们想找e1表中的某些记录,这
些记录的m1列的值能在e2表的m2列找到匹配的值。

子查询出现在ORDER BY子句、GROUP BY子句中

虽然语法支持,但没啥意义。

子查询的分类

按返回的结果集区分子查询

因为子查询本身也算是一个查询,所以可以按照它们返回的不同结果集类型
而把这些子查询分为不同的类型:

标量子查询

那些只返回一个单一值的子查询称之为标量子查询,比如这样:

SELECT (SELECT m1 FROM e1 LIMIT 1);

或者这样:

SELECT * FROM e1 WHERE m1 = (SELECT MIN(m2) FROM e2);
SELECT * FROM e1 WHERE m1 < (SELECT MIN(m2) FROM e2);

这两个查询语句中的子查询都返回一个单一的值,也就是一个标量。这些标
量子查询可以作为一个单一值或者表达式的一部分出现在查询语句的各个地方。

行子查询

顾名思义,就是返回一条记录的子查询,不过这条记录需要包含多个列(只
包含一个列就成了标量子查询了)。比如这样:

SELECT * FROM e1 WHERE (m1, n1) = (SELECT m2, n2 FROM e2 LIMIT 1);

其中的(SELECT m2, n2 FROM e2 LIMIT 1)就是一个行子查询,整条语句的含义
就是要从e1表中找一些记录,这些记录的m1和n1列分别等于子查询结果中的
m2 和n2列。

列子查询

列子查询自然就是查询出一个列的数据喽,不过这个列的数据需要包含多条
记录(只包含一条记录就成了标量子查询了)。比如这样:

SELECT * FROM e1 WHERE m1 IN (SELECT m2 FROM e2);

其中的(SELECT m2 FROM e2)就是一个列子查询,表明查询出e2表的m2列
的值作为外层查询IN语句的参数。

表子查询

顾名思义,就是子查询的结果既包含很多条记录,又包含很多个列,比如这
样:

SELECT * FROM e1 WHERE (m1, n1) IN (SELECT m2, n2 FROM e2);

其中的(SELECT m2, n2 FROM e2)就是一个表子查询,这里需要和行子查询对
比一下,行子查询中我们用了LIMIT 1来保证子查询的结果只有一条记录,表子
查询中不需要这个限制。

按与外层查询关系来区分子查询

不相关子查询

如果子查询可以单独运行出结果,而不依赖于外层查询的值,我们就可以把
这个子查询称之为不相关子查询。我们前边介绍的那些子查询全部都可以看作不
相关子查询。

相关子查询

如果子查询的执行需要依赖于外层查询的值,我们就可以把这个子查询称之
为相关子查询。比如:

SELECT * FROM e1 WHERE m1 IN (SELECT m2 FROM e2 WHERE n1 = n2);

例子中的子查询是(SELECT m2 FROM e2 WHERE n1 = n2),可是这个查询中有
一个搜索条件是n1=n2,别忘了n1是表e1的列,也就是外层查询的列,也就
是说子查询的执行需要依赖于外层查询的值,所以这个子查询就是一个相关子查
询。

[NOT] IN/ANY/SOME/ALL 子查询

对于列子查询和表子查询来说,它们的结果集中包含很多条记录,这些记录
相当于是一个集合,所以就不能单纯的和另外一个操作数使用操作符来组成布尔
表达式了,MySQL通过下面的语法来支持某个操作数和一个集合组成一个布尔表
达式:

IN或者NOT IN

具体的语法形式如下:

操作数 [NOT] IN (子查询)

这个布尔表达式的意思是用来判断某个操作数在不在由子查询结果集组成
的集合中,比如下边的查询的意思是找出e1表中的某些记录,这些记录存在于
子查询的结果集中:

SELECT * FROM e1 WHERE (m1, n1) IN (SELECT m2, n2 FROM e2);

ANY/SOME(ANY和SOME是同义词)

具体的语法形式如下:

操作数 比较符 ANY/SOME(子查询)

这个布尔表达式的意思是只要子查询结果集中存在某个值和给定的操作数
做比较操作,比较结果为TRUE,那么整个表达式的结果就为TRUE,否则整个表
达式的结果就为FALSE。比方说下边这个查询:

SELECT * FROM e1 WHERE m1 > ANY(SELECT m2 FROM e2);

这个查询的意思就是对于e1表的某条记录的m1列的值来说,如果子查询
(SELECT m2 FROM e2)的结果集中存在一个小于m1列的值,那么整个布尔表达式
的值就是TRUE,否则为FALSE,也就是说只要m1列的值大于子查询结果集中最
小的值,整个表达式的结果就是TRUE,所以上边的查询本质上等价于这个查询:

SELECT * FROM e1 WHERE m1 > (SELECT MIN(m2) FROM e2);

另外,=ANY相当于判断子查询结果集中是否存在某个值和给定的操作数相
等,它的含义和IN是相同的。

ALL

具体的语法形式如下:

操作数 比较操作 ALL(子查询)

这个布尔表达式的意思是子查询结果集中所有的值和给定的操作数做比较
操作比较结果为TRUE,那么整个表达式的结果就为TRUE,否则整个表达式的结
果就为FALSE。比方说下边这个查询:

SELECT * FROM e1 WHERE m1 > ALL(SELECT m2 FROM e2);

这个查询的意思就是对于e1表的某条记录的m1列的值来说,如果子查询
(SELECT m2 FROM e2)的结果集中的所有值都小于m1列的值,那么整个布尔表达
式的值就是TRUE,否则为FALSE,也就是说只要m1列的值大于子查询结果集中
最大的值,整个表达式的结果就是 TRUE,所以上边的查询本质上等价于这个查
询:

SELECT * FROM e1 WHERE m1 > (SELECT MAX(m2) FROM e2);

EXISTS子查询

有的时候我们仅仅需要判断子查询的结果集中是否有记录,而不在乎它的记
录具体是个啥,可以使用把EXISTS或者NOT EXISTS放在子查询语句前边,就像
这样:

SELECT * FROM e1 WHERE EXISTS (SELECT 1 FROM e2);

对于子查询(SELECT 1 FROM e2)来说,我们并不关心这个子查询最后到底查
询出的结果是什么,所以查询列表里填*、某个列名,或者其他啥东西都无所谓,
我们真正关心的是子查询的结果集中是否存在记录。也就是说只要(SELECT 1
FROM e2)这个查询中有记录,那么整个EXISTS表达式的结果就为TRUE。

子查询语法注意事项

  • 子查询必须用小括号扩起来。

  • 在SELECT子句中的子查询必须是标量子查询,如果子查询结果集中有多个
    列或者多个行,都不允许放在SELECT子句中,在想要得到标量子查询或者行子
    查询,但又不能保证子查询的结果集只有一条记录时,应该使用LIMIT 1语句来
    限制记录数量。

  • 对于[NOT] IN/ANY/SOME/ALL子查询来说,子查询中不允许有LIMIT语句,
    而且这类子查询中ORDER BY子句、DISTINCT语句、没有聚集函数以及HAVING
    子句的GROUP BY子句没有什么意义。因为子查询的结果其实就相当于一个集合,
    集合里的值排不排序等一点儿都不重要。

  • 不允许在一条语句中增删改某个表的记录时同时还对该表进行子查询。

子查询在 MySQL 中是怎么执行的

想象子查询的执行方式

想象中子查询的执行方式是这样的:

如果该子查询是不相关子查询,比如下边这个查询:


SELECT * FROM s1 WHERE order_note IN (SELECT order_note FROM s2);

先单独执行(SELECT order_note FROM s2)这个子查询。然后在将上一步子查
询得到的结果当作外层查询的参数再执行外层查询SELECT * FROM s1 WHERE
order_note IN (…)。

如果该子查询是相关子查询,比如下边这个查询:

SELECT * FROM s1 WHERE order_note IN (SELECT order_note FROM s2 WHERE
 s1.order_no= s2.order_no);

这个查询中的子查询中出现了s1.order_no= s2.order_no这样的条件,意味
着该子查询的执行依赖着外层查询的值,先从外层查询中获取一条记录,本例中
也就是先从s1表中获取一条记录,然后执行子查询。
最后根据子查询的查询结果来检测外层查询WHERE子句的条件是否成立,
如果成立,就把外层查询的那条记录加入到结果集,否则就丢弃。
再次执行第一步,获取第二条外层查询中的记录,依次类推。

但真的是这样吗?其实MySQL用了一系列的办法来优化子查询的执行,大
部分情况下这些优化措施其实挺有效的,下边我们来看看各种不同类型的子查询
具体是怎么执行的。

标量子查询、行子查询的执行方式

对于不相关标量子查询或者行子查询来说,它们的执行方式很简单,比方说
下边这个查询语句:

SELECT * FROM s1 WHERE order_note = (SELECT order_note FROM s2 WHERE
 key3 = 'a' LIMIT 1);

它的执行方式和我们前面想象的一样:先单独执行(SELECT order_note FROM
s2 WHERE key3 = ‘a’ LIMIT 1)这个子查询。然后在将上一步子查询得到的结果当作
外层查询的参数再执行外层查询SELECT * FROM s1 WHERE order_note= …。

也就是说,对于包含不相关的标量子查询或者行子查询的查询语句来说,
MySQL会分别独立的执行外层查询和子查询,就当作两个单表查询就好了。

对于相关的标量子查询或者行子查询来说,比如下边这个查询:

SELECT * FROM s1 WHERE
 order_note = (SELECT order_note FROM s2 WHERE s1.order_no=
 s2.order_no LIMIT 1);

事情也和我们前面想象的一样,它的执行方式就是这样的:

先从外层查询中获取一条记录,本例中也就是先从 s1 表中获取一条记录。
然后从上一步骤中获取的那条记录中找出子查询中涉及到的值,本例中就是
从s1表中获取的那条记录中找出s1.order_no列的值,然后执行子查询。
最后根据子查询的查询结果来检测外层查询WHERE子句的条件是否成立,
如果成立,就把外层查询的那条记录加入到结果集,否则就丢弃。
再次执行第一步,获取第二条外层查询中的记录,依次类推。

也就是说对于两种使用标量子查询以及行子查询的场景中,MySQL优化器的
执行方式并没有什么新鲜的。

MySQL对IN子查询的优化

物化表

对于不相关的IN子查询,比如这样:

SELECT * FROM s1 WHERE order_note IN (SELECT order_note FROM s2 WHERE
 order_no = 'a');

我们最开始的感觉就是这种不相关的IN子查询和不相关的标量子查询或者
行子查询是一样一样的,都是把外层查询和子查询当作两个独立的单表查询来对
待。但是MySQL为了优化IN子查询下了很大力气,所以整个执行过程并不像我
们想象的那么简单。

对于不相关的IN子查询来说,如果子查询的结果集中的记录条数很少,那
么把子查询和外层查询分别看成两个单独的单表查询效率很高,但是如果单独执
行子查询后的结果集太多的话,就会导致这些问题:

  • 结果集太多,可能内存中都放不下。

  • 对于外层查询来说,如果子查询的结果集太多,那就意味着IN子句中的
    参数特别多,这就导致:无法有效的使用索引,只能对外层查询进行全表扫描。

在对外层查询执行全表扫描时,由于IN子句中的参数太多,这会导致检测
一条记录是否符合和IN子句中的参数匹配花费的时间太长。

比如说IN子句中的参数只有两个:

SELECT * FROM tbl_name WHERE column IN (a, b);

这样相当于需要对tbl_name表中的每条记录判断一下它的column列是否符
合column = a OR column = b。在IN子句中的参数比较少时这并不是什么问题,
如果IN子句中的参数比较多时,比如这样:

SELECT * FROM tbl_name WHERE column IN (a, b, c ..., ...);

那么这样每条记录需要判断一下它的column列是否符合column = a OR
column = b OR column = c OR …,这样性能耗费可就多了。

MySQL的改进是不直接将不相关子查询的结果集当作外层查询的参数,而是
将该结果集写入一个临时表里。写入临时表的过程是这样的:

1、该临时表的列就是子查询结果集中的列。

2、写入临时表的记录会被去重,临时表也是个表,只要为表中记录的所有
列建立主键或者唯一索引。

一般情况下子查询结果集不会大的离谱,所以会为它建立基于内存的使用
Memory存储引擎的临时表,而且会为该表建立哈希索引。

如果子查询的结果集非常大,超过了系统变量tmp_table_size或者
max_heap_table_size,临时表会转而使用基于磁盘的存储引擎来保存结果集中的
记录,索引类型也对应转变为B+树索引。

MySQL把这个将子查询结果集中的记录保存到临时表的过程称之为物化(Materialize)。为了方便起见,我们就把那个存储子查询结果集的临时表

称之为物化表。正因为物化表中的记录都建立了索引(基于内存的物化表有哈希
索引,基于磁盘的有 B+树索引),通过索引执行IN语句判断某个操作数在不在
子查询结果集中变得非常快,从而提升了子查询语句的性能。

物化表转连接

事情到这就完了?我们还得重新审视一下最开始的那个查询语句:

SELECT * FROM s1 WHERE order_note IN (SELECT order_note FROM s2 WHERE
 order_no = 'a');

当我们把子查询进行物化之后,假设子查询物化表的名称为
materialized_table,该物化表存储的子查询结果集的列为m_val,那么这个查询
就相当于表s1和子查询物化表materialized_table进行内连接:

SELECT s1.* FROM s1 INNER JOIN materialized_table ON order_note = m_val;

转化成内连接之后就有意思了,查询优化器可以评估不同连接顺序需要的成
本是多少,选取成本最低的那种查询方式执行查询。

将子查询转换为 semi-join

虽然将子查询进行物化之后再执行查询都会有建立临时表的成本,但是不管
怎么说,我们见识到了将子查询转换为连接的强大作用,MySQL继续开脑洞:能
不能不进行物化操作直接把子查询转换为连接呢?让我们重新审视一下上边的
查询语句:

SELECT * FROM s1 WHERE order_note IN (SELECT order_note FROM s2 WHERE
 order_no = 'a');

我们可以把这个查询理解成:对于s1表中的某条记录,如果我们能在s2表
(准确的说是执行完WHERE s2.order_no= 'a’之后的结果集)中找到一条或多条记
录,这些记录的order_note的值等于s1表记录的order_note列的值,那么该条
s1表的记录就会被加入到最终的结果集。这个过程其实和把s1和 s2两个表连接
起来的效果很像:

SELECT s1.* FROM s1 INNER JOIN s2
 ON s1.order_note = s2.order_note
 WHERE s2.order_no= 'a';

只不过我们不能保证对于s1表的某条记录来说,在s2表(准确的说是执行
完WHERE s2.order_no= 'a’之后的结果集)中有多少条记录满足s1.order_no=
s2.order_no这个条件,不过我们可以分三种情况讨论:

情况一:对于s1表的某条记录来说,s2表中没有任何记录满足s1.order_note = s2.order_note这个条件,那么该记录自然也不会加入到最后的结果集。

情况二:对于s1表的某条记录来说,s2 表中有且只有1条记录满足
s1.order_note = s2.order_note这个条件,那么该记录会被加入最终的结果集。

情况三:对于s1表的某条记录来说,s2 表中至少有2条记录满足
s1.order_note = s2.order_note这个条件,那么该记录会被多次加入最终的结果集。

对于s1表的某条记录来说,由于我们只关心s2表中是否存在记录满足
s1.order_no = s2.order_note这个条件,而不关心具体有多少条记录与之匹配,又
因为有情况三的存在,我们上边所说的IN子查询和两表连接之间并不完全等价。

但是将子查询转换为连接又真的可以充分发挥优化器的作用,所以MySQL在这
里提出了一个新概念 — 半连接(semi-join)。

将s1表和s2表进行半连接的意思就是:对于 s1 表的某条记录来说,我们
只关心在 s2 表中是否存在与之匹配的记录,而不关心具体有多少条记录与之匹
配,最终的结果集中只保留s1表的记录。为了让大家有更直观的感受,我们假
设MySQL内部是这么改写上边的子查询的:

SELECT s1.* FROM s1 SEMI JOIN s2
 ON s1.order_note = s2.order_note
 WHERE order_no= 'a';

注意:semi-join只是在 MySQL 内部采用的一种执行子查询的方式,MySQL
并没有提供面向用户的semi-join语法。

概念是有了,怎么实现这种所谓的半连接呢?MySQL准备了好几种办法。

Table pullout (子查询中的表上拉)

当子查询的查询列表处只有主键或者唯一索引列时,可以直接把子查询中的
表上拉到外层查询的FROM子句中,并把子查询中的搜索条件合并到外层查询的
搜索条件中,比如假设s2中存在这个一个key2列,列上有唯一性索引:

SELECT * FROM s1
 WHERE key2 IN (SELECT key2 FROM s2 WHERE key3 = 'a');

由于key2列是s2表的唯一二级索引列,所以我们可以直接把s2表上拉到
外层查询的 FROM 子句中,并且把子查询中的搜索条件合并到外层查询的搜索条
件中,上拉之后的查询就是这样的:

SELECT s1.* FROM s1 INNER JOIN s2
 ON s1.key2 = s2.key2
 WHERE s2.key3 = 'a';

为啥当子查询的查询列表处只有主键或者唯一索引列时,就可以直接将子查
询转换为连接查询呢?因为主键或者唯一索引列中的数据本身就是不重复的嘛!
所以对于同一条s1表中的记录,你不可能找到两条以上的符合s1.key2=s2.key2
的记录。

DuplicateWeedout execution strategy (重复值消除)

对于这个查询来说:

SELECT * FROM s1 WHERE order_note IN (SELECT order_note FROM s2 WHERE
 order_no= 'a');

转换为半连接查询后,s1表中的某条记录可能在s2表中有多条匹配的记录,
所以该条记录可能多次被添加到最后的结果集中,为了消除重复,我们可以建立
一个临时表,比方说这个临时表长这样:

CREATE TABLE tmp (
id PRIMARY KEY
);

这样在执行连接查询的过程中,每当某条s1表中的记录要加入结果集时,
就首先把这条记录的id值加入到这个临时表里,如果添加成功,说明之前这条
s1表中的记录并没有加入最终的结果集,现在把该记录添加到最终的结果集;
如果添加失败,说明之前这条s1表中的记录已经加入过最终的结果集,这里直
接把它丢弃就好了,这种使用临时表消除semi-join结果集中的重复值的方式称
之为DuplicateWeedout。

LooseScan execution strategy (松散扫描)

大家看这个查询:

SELECT * FROM s1 WHERE order_note IN (SELECT order_no FROM s2 WHERE
 order_no> 'a' AND order_no< 'b');

在子查询中,对于s2表的访问可以使用到order_no列的索引,而恰好子查
询的查询列表处就是order_no列,这样在将该查询转换为半连接查询后,如果
将s2作为驱动表执行查询的话,那么执行过程就是这样:

在s2表的idx_order_no索引中,值为’aa’的二级索引记录一共有3条,那么
只需要取第一条的值到s1表中查找s1.order_note= 'aa’的记录,如果能在s1 表中
找到对应的记录,那么就把对应的记录加入到结果集。依此类推,其他值相同的
二级索引记录,也只需要取第一条记录的值到s1表中找匹配的记录,这种虽然
是扫描索引,但只取值相同的记录的第一条去做匹配操作的方式称之为松散扫描。

当然除了我们上面所说的,MySQL中的半连接方式还有好几种,比如
Semi-join Materializationa 半连接物化、FirstMatch execution strategy (首次匹配)
等等,我们就不更深入的讨论了。

semi-join的适用条件

当然,并不是所有包含IN子查询的查询语句都可以转换为semi-join,只有
形如这样的查询才可以被转换为semi-join:

SELECT ... FROM outer_tables
 WHERE expr IN (SELECT ... FROM inner_tables ...) AND ... 

或者这样的形式也可以:

SELECT ... FROM outer_tables
 WHERE (oe1, oe2, ...) IN (SELECT ie1, ie2, ... FROM inner_tables ...) AND ... 

用文字总结一下,只有符合下边这些条件的子查询才可以被转换为 semi-join:

  • 该子查询必须是和 IN 语句组成的布尔表达式,并且在外层查询的 WHERE 或
    者 ON 子句中出现。

  • 外层查询也可以有其他的搜索条件,只不过和 IN 子查询的搜索条件必须使
    用 AND 连接起来。

  • 该子查询必须是一个单一的查询,不能是由若干查询由 UNION 连接起来的
    形式。

  • 该子查询不能包含 GROUP BY 或者 HAVING 语句或者聚集函数。

MySQL对不能转为semi-join查询的子查询优化

1、对于不相关子查询来说,可以尝试把它们物化之后再参与查询
比如我们上边提到的这个查询:

SELECT * FROM s1 WHERE order_note NOT IN (SELECT order_note FROM s2
 WHERE order_no= 'a')

先将子查询物化,然后再判断order_note是否在物化表的结果集中可以加
快查询执行的速度。

2、不管子查询是相关的还是不相关的,都可以把IN子查询尝试转为EXISTS
子查询
其实对于任意一个IN子查询来说,都可以被转为EXISTS子查询,通用的例
子如下:

outer_expr IN (SELECT inner_expr FROM ... WHERE subquery_where)

可以被转换为:

EXISTS (SELECT inner_expr FROM ... WHERE subquery_where AND
 outer_expr=inner_expr)

为啥要转换呢?这是因为不转换的话可能用不到索引,比方说下边这个查询:

SELECT * FROM s1 WHERE order_no IN (SELECT order_no FROM s2 where
 s1.order_note = s2.order_note) OR insert_time >2021-03-22 18:28:28;

这个查询中的子查询是一个相关子查询,而且子查询执行的时候不能使用到
索引,但是将它转为EXISTS子查询后却可以使用到索引:

SELECT * FROM s1 WHERE EXISTS (SELECT 1 FROM s2 where s1.order_note =
 s2.order_note AND s2.order_no= s1.order_no) OR insert_time >2021-03-22
 18:28:2800;

转为EXISTS子查询时便可能使用到s2表的idx_order_no索引了。
需要注意的是,如果IN子查询不满足转换为semi-join的条件,又不能转换
为物化表或者转换为物化表的成本太大,那么它就会被转换为EXISTS查询。
在MySQL5.5以及之前的版本没有引进semi-join和物化的方式优化子查询时,
优化器都会把IN子查询转换为EXISTS子查询,所以当时好多声音都是建议大家
把子查询转为连接,不过随着MySQL的发展,最近的版本中引入了非常多的子
查询优化策略,内部的转换工作优化器会为大家自动实现。

  • 1
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
言 1. 一般信息 1.1. 关于本手册 1.2. 本手册采用的惯例 1.3. MySQL AB概述 1.4. MySQL数据库管理系统概述 1.4.1. MySQL的历史 1.4.2. MySQL的的主要特性 1.4.3. MySQL稳定性 1.4.4. MySQL表最大能达到多少 1.4.5. 2000年兼容性 1.5. MaxDB数据库管理系统概述 1.5.1. 什么是MaxDB? 1.5.2. MaxDB的历史 1.5.3. MaxDB的特性 1.5.4. 许可和支持 1.5.5. MaxDB和MySQL之间的特性差异 1.5.6. MaxDB和MySQL之间的协同性 1.5.7. 与MaxDB有关的链接 1.6. MySQL发展大事记 1.6.1. MySQL 5.1的新特性 1.7. MySQL信息源 1.7.1. MySQL邮件列表 1.7.2. IRC(在线聊天系统)上的MySQL社区支持 1.7.3. MySQL论坛上的MySQL社区支持 1.8. MySQL标准的兼容性 1.8.1. MySQL遵从的标准是什么 1.8.2. 选择SQL模式 1.8.3. 在ANSI模式下运行MySQL 1.8.4. MySQL对标准SQL的扩展 1.8.5. MySQL与标准SQL的差别 1.8.6. MySQL处理约束的方式 2. 安装MySQL 2.1. 一般安装问题 2.1.1. MySQL支持的操作系统 2.1.2. 选择要安装的MySQL分发版 2.1.3. 怎样获得MySQL 2.1.4. 通过MD5校验和或GnuPG验证软件包的完整性 2.1.5. 安装布局 2.2. 使用二进制分发版的标准MySQL安装 2.3. 在Windows上安装MySQL 2.3.1. Windows系统要求 2.3.2. 选择安装软件包 2.3.3. 用自动安装器安装MySQL 2.3.4. 使用MySQL安装向导 2.3.5. 使用配置向导 2.3.6. 通过非安装Zip文件安装MySQL 2.3.7. 提取安装档案文件 2.3.8. 创建选项文件 2.3.9. 选择MySQL服务器类型 2.3.10. 首次启动服务器 2.3.11. 从Windows命令行启动MySQL 2.3.12. 以Windows服务方式启动MySQL 2.3.13. 测试MySQL安装 2.3.14. 在Windows环境下对MySQL安装的故障诊断与排除 2.3.15. 在Windows下升级MySQL 2.3.16. Windows版MySQL同Unix版MySQL对比 2.4. 在Linux下安装MySQL 2.5.在Mac OS X中安装MySQL 2.6. 在NetWare中安装MySQL 2.7. 在其它类Unix系统中安装MySQL 2.8. 使用源码分发版安装MySQL 2.8.1. 源码安装概述 2.8.2. 典型配置选项 2.8.3. 从开发源码树安装 2.8.4. 处理MySQL编译问题 2.8.5. MIT-pthreads注意事项 2.8.6. 在Windows下从源码安装MySQL 2.8.7. 在Windows下编译MySQL客户端 2.9. 安装后的设置和测试 2.9.1. Windows下安装后的过程 2.9.2. Unix下安装后的过程 2.9.3. 使初始MySQL账户安全 2.10. 升级MySQL 2.10.1. 从5.0版升级 2.10.2. 升级授权表 2.10.3. 将MySQL数据库拷贝到另一台机器 2.11. 降级MySQL 2.12. 具体操作系统相关的注意事项 2.12.1. Linux注意事项 2.12.2. Mac OS X注意事项 2.12.3. Solaris注意事项 2.12.4. BSD注意事项 2.12.5. 其它Unix注意事项 2.12.6. OS/2注意事项 2.13. Perl安装注意事项 2.13.1. 在Unix中安装Perl 2.13.2. 在Windows下安装ActiveState Perl 2.13.3. 使用Perl DBI/DBD接口的问题 3. 教程 3.1. 连接与断开服务器 3.2. 输入查询 3.3. 创建并使用数据库 3.3.1. 创建并选择数据库 3.3.2. 创建表 3.3.3. 将数据装入表中 3.3.4. 从表检索信息 3.4. 获得数据库和表的信息 3.5. 在批处理模式下使用mysql 3.6. 常用查询的例子 3.6.1. 列的最大值 3.6.2. 拥有某个列的最大值的行 3.6.3. 列的最大值:按组 3.6.4. 拥有某个字段的组间最大值的行 3.6.5. 使用用户变量 3.6.6. 使用外键 3.6.7. 根据两个键搜索 3.6.8. 根据天计算访问量 3.6.9. 使用AUTO_INCREMENT 3.7. 孪生项目的查询 3.7.1. 查找所有未分发的孪生项 3.7.2. 显示孪生对状态的表 3.8. 与Apache一起使用MySQL 4. MySQL程序概述 4.1. MySQL程序概述 4.2. 调用MySQL程序 4.3. 指定程序选项 4.3.1. 在命令行上使用选项 4.3.2. 使用选项文件 4.3.3. 用环境变量指定选项 4.3.4. 使用选项设置程序变量 5. 数据库管理 5.1. MySQL服务器和服务器启动脚本 5.1.1. 服务器端脚本和实用工具概述 5.1.2. mysqld-max扩展MySQL服务器 5.1.3. mysqld_safe:MySQL服务器启动脚本 5.1.4. mysql.server:MySQL服务器启动脚本 5.1.5. mysqld_multi:管理多个MySQL服务器的程序 5.2. mysqlmanager:MySQL实例管理器 5.2.1. 用MySQL实例管理器启动MySQL服务器 5.2.2. 连接MySQL实例管理器并创建用户账户 5.2.3. MySQL实例管理器命令行选项 5.2.4. MySQL实例管理器配置文件 5.2.5. MySQL实例管理器识别的命令 5.3. mysqld:MySQL服务器 5.3.1. mysqld命令行选项 5.3.2. SQL服务器模式 5.3.3. 服务器系统变量 5.3.4. 服务器状态变量 5.4. mysql_fix_privilege_tables:升级MySQL系统表 5.5. MySQL服务器关机进程 5.6. 一般安全问题 5.6.1. 通用安全指南 5.6.2. 使MySQL在攻击者面前保持安全 5.6.3. Mysqld安全相关启动选项 5.6.4. LOAD DATA LOCAL安全问题 5.7. MySQL访问权限系统 5.7.1. 权限系统的作用 5.7.2. 权限系统工作原理 5.7.3. MySQL提供的权限 5.7.4. 与MySQL服务器连接 5.7.5. 访问控制, 阶段1:连接核实 5.7.6. 访问控制, 阶段2:请求核实 5.7.7. 权限更改何时生效 5.7.8. 拒绝访问错误的原因 5.7.9. MySQL 4.1中的密码哈希处理 5.8. MySQL用户账户管理 5.8.1. MySQL用户名和密码 5.8.2. 向MySQL增加新用户账户 5.8.3. 从MySQL删除用户账户 5.8.4. 限制账户资源 5.8.5. 设置账户密码 5.8.6. 使你的密码安全 5.8.7. 使用安全连接 5.9. 备份与恢复 5.9.1. 数据库备份 5.9.2. 示例用备份与恢复策略 5.9.3. 自动恢复 5.9.4. 表维护和崩溃恢复 5.9.5. myisamchk:MyISAM表维护实用工具 5.9.6. 建立表维护计划 5.9.7. 获取关于表的信息 5.10. MySQL本地化和国际应用 5.10.1. 数据和排序用字符集 5.10.2. 设置错误消息语言 5.10.3. 添加新的字符集 5.10.4. 字符定义数组 5.10.5. 字符串比较支持 5.10.6. 多字节字符支持 5.10.7. 字符集问题 5.10.8. MySQL服务器时区支持 5.11. MySQL日志文件 5.11.1. 错误日志 5.11.2. 通用查询日志 5.11.3. 二进制日志 5.11.4. 慢速查询日志 5.11.5. 日志文件维护 5.12. 在同一台机器上运行多个MySQL服务器 5.12.1. 在Windows下运行多个服务器 5.12.2. 在Unix中运行多个服务器 5.12.3. 在多服务器环境中使用客户端程序 5.13. MySQL查询高速缓冲 5.13.1. 查询高速缓冲如何工作 5.13.2. 查询高速缓冲SELECT选项 5.13.3. 查询高速缓冲配置 5.13.4. 查询高速缓冲状态和维护 6. MySQL中的复制 6.1. 复制介绍 6.2. 复制实施概述 6.3. 复制实施细节 6.3.1. 复制主线程状态 6.3.2. 复制从I/O线程状态 6.3.3. 复制从SQL线程状态 6.3.4. 复制传递和状态文件 6.4. 如何设置复制 6.5. 不同MySQL版本之间的复制兼容性 6.6. 升级复制设置 6.6.1. 将复制升级到5.0版 6.7. 复制特性和已知问题 6.8. 复制启动选项 6.9. 复制FAQ 6.10. 复制故障诊断与排除 6.11. 通报复制缺陷 6.12. 多服务器复制中的Auto-Increment 7. 优化 7.1. 优化概述 7.1.1. MySQL设计局限与折衷 7.1.2. 为可移植性设计应用程序 7.1.3. 我们已将MySQL用在何处? 7.1.4. MySQL基准套件 7.1.5. 使用自己的基准 7.2. 优化SELECT语句和其它查询 7.2.1. EXPLAIN语法(获取SELECT相关信息) 7.2.2. 估计查询性能 7.2.3. SELECT查询的速度 7.2.4. MySQL怎样优化WHERE子句 7.2.5. 范围优化 7.2.6. 索引合并优化 7.2.7. MySQL如何优化IS NULL 7.2.8. MySQL如何优化DISTINCT 7.2.9. MySQL如何优化LEFT JOIN和RIGHT JOIN 7.2.10. MySQL如何优化嵌套Join 7.2.11. MySQL如何简化外部联合 7.2.12. MySQL如何优化ORDER BY 7.2.13. MySQL如何优化GROUP BY 7.2.14. MySQL如何优化LIMIT 7.2.15. 如何避免表扫描 7.2.16. INSERT语句的速度 7.2.17. UPDATE语句的速度 7.2.18. DELETE语句的速度 7.2.19. 其它优化技巧 7.3. 锁定事宜 7.3.1. 锁定方法 7.3.2. 表锁定事宜 7.4. 优化数据库结构 7.4.1. 设计选择 7.4.2. 使你的数据尽可能小 7.4.3. 列索引 7.4.4. 多列索引 7.4.5. MySQL如何使用索引 7.4.6. MyISAM键高速缓冲 7.4.7. MyISAM索引统计集合 7.4.8. MySQL如何计算打开的表 7.4.9. MySQL如何打开和关闭表 7.4.10. 在同一个数据库中创建多个表的缺陷 7.5. 优化MySQL服务器 7.5.1. 系统因素和启动参数的调节 7.5.2. 调节服务器参数 7.5.3. 控制查询优化器的性能 7.5.4. 编译和链接怎样影响MySQL的速度 7.5.5. MySQL如何使用内存 7.5.6. MySQL如何使用DNS 7.6. 磁盘事宜 7.6.1. 使用符号链接 8. 客户端和实用工具程序 8.1. 客户端脚本和实用工具概述 8.2. myisampack:生成压缩、只读MyISAM表 8.3. mysqlMySQL命令行工具 8.3.1. 选项 8.3.2. mysql命令 8.3.3. 怎样从文本文件执行SQL语句 8.3.4. mysql技巧 8.4. mysqlaccess:用于检查访问权限的客户端 8.5. mysqladmin:用于管理MySQL服务器的客户端 8.6. mysqlbinlog:用于处理二进制日志文件的实用工具 8.7. mysqlcheck:表维护和维修程序 8.8. mysqldump:数据库备份程序 8.9. mysqlhotcopy:数据库备份程序 8.10. mysqlimport:数据导入程序 8.11. mysqlshow-显示数据库、表和列信息 8.12. myisamlog:显示MyISAM日志文件内容 8.13. perror:解释错误代码 8.14. replace:字符串替换实用工具 8.15. mysql_zap:杀死符合某一模式的进程 9. 语言结构 9.1. 文字值 9.1.1. 字符串 9.1.2. 数值 9.1.3. 十六进制值 9.1.4. 布尔值 9.1.5. 位字段值 9.1.6. NULL值 9.2. 数据库、表、索引、列和别名 9.2.1. 识别符限制条件 9.2.2. 识别符大小写敏感性 9.3. 用户变量 9.4. 系统变量 9.4.1. 结构式系统变量 9.5. 注释语法 9.6. MySQL中保留字的处理 10. 字符集支持 10.1. 常规字符集和校对 10.2. MySQL中的字符集和校对 10.3. 确定默认字符集和校对 10.3.1. 服务器字符集和校对 10.3.2. 数据库字符集和校对 10.3.3. 表字符集和校对 10.3.4. 列字符集和校对 10.3.5. 字符集和校对分配示例 10.3.6. 连接字符集和校对 10.3.7. 字符串文字字符集和校对 10.3.8. 在SQL语句中使用COLLATE 10.3.9. COLLATE子句优先 10.3.10. BINARY操作符 10.3.11. 校对确定较为复杂的一些特殊情况 10.3.12. 校对必须适合字符集 10.3.13. 校对效果的示例 10.4. 字符集支持影响到的操作 10.4.1. 结果字符串 10.4.2. CONVERT() 10.4.3. CAST() 10.4.4. SHOW语句 10.5. Unicode支持 10.6. 用于元数据的UTF8 10.7. 与其它DBMS的兼容性 10.8. 新字符集配置文件格式 10.9. 国家特有字符集 10.10. MySQL支持的字符集和校对 10.10.1. Unicode字符集 10.10.2. 西欧字符集 10.10.3. 中欧字符集 10.10.4. 南欧与中东字符集 10.10.5. 波罗的海字符集 10.10.6. 西里尔字符集 10.10.7. 亚洲字符集 11. 列类型 11.1. 列类型概述 11.1.1. 数值类型概述 11.1.2. 日期和时间类型概述 11.1.3. 字符串类型概述 11.2. 数值类型 11.3. 日期和时间类型 11.3.1. DATETIME、DATE和TIMESTAMP类型 11.3.2. TIME类型 11.3.3. YEAR类型 11.3.4. Y2K事宜和日期类型 11.4. String类型 11.4.1. CHAR和VARCHAR类型 11.4.2. BINARY和VARBINARY类型 11.4.3. BLOB和TEXT类型 11.4.4. ENUM类型 11.4.5. SET类型 11.5. 列类型存储需求 11.6. 选择正确的列类型 11.7. 使用来自其他数据库引擎的列类型 12. 函数和操作符 12.1. 操作符 12.1.1. 操作符优先级 12.1.2. 圆括号 12.1.3. 比较函数和操作符 12.1.4. 逻辑操作符 12.2. 控制流程函数 12.3. 字符串函数 12.3.1. 字符串比较函数 12.4. 数值函数 12.4.1. 算术操作符 12.4.2. 数学函数 12.5. 日期和时间函数 12.6. MySQL使用什么日历? 12.7. 全文搜索功能 12.7.1. 布尔全文搜索 12.7.2. 全文搜索带查询扩展 12.7.3. 全文停止字 12.7.4. 全文限定条件 12.7.5. 微调MySQL全文搜索 12.8. Cast函数和操作符 12.9. 其他函数 12.9.1. 位函数 12.9.2. 加密函数 12.9.3. 信息函数 12.9.4. 其他函数 12.10. 与GROUP BY子句同时使用的函数和修改程序 12.10.1. GROUP BY(聚合)函数 12.10.2. GROUP BY修改程序 12.10.3. 具有隐含字段的GROUP BY 13. SQL语句语法 13.1. 数据定义语句 13.1.1. ALTER DATABASE语法 13.1.2. ALTER TABLE语法 13.1.3. CREATE DATABASE语法 13.1.4. CREATE INDEX语法 13.1.5. CREATE TABLE语法 13.1.6. DROP DATABASE语法 13.1.7. DROP INDEX语法 13.1.8. DROP TABLE语法 13.1.9. RENAME TABLE语法 13.2. 数据操作语句 13.2.1. DELETE语法 13.2.2. DO语法 13.2.3. HANDLER语法 13.2.4. INSERT语法 13.2.5. LOAD DATA INFILE语法 13.2.6. REPLACE语法 13.2.7. SELECT语法 13.2.8. Subquery语法 13.2.9. TRUNCATE语法 13.2.10. UPDATE语法 13.3. MySQL实用工具语句 13.3.1. DESCRIBE语法(获取有关列的信息) 13.3.2. USE语法 13.4. MySQL事务处理和锁定语句 13.4.1. START TRANSACTION, COMMIT和ROLLBACK语法 13.4.2. 不能回滚的语句 13.4.3. 会造成隐式提交的语句 13.4.4. SAVEPOINT和ROLLBACK TO SAVEPOINT语法 13.4.5. LOCK TABLES和UNLOCK TABLES语法 13.4.6. SET TRANSACTION语法 13.4.7. XA事务 13.5. 数据库管理语句 13.5.1. 账户管理语句 13.5.2. 表维护语句 13.5.3. SET语法 13.5.4. SHOW语法 13.5.5. 其它管理语句 13.6. 复制语句 13.6.1. 用于控制主服务器的SQL语句 13.6.2. 用于控制从服务器的SQL语句 13.7. 用于预处理语句的SQL语法 14. 插件式存储引擎体系结构 14.1. 前言 14.2. 概述 14.3. 公共MySQL数据库服务器层 14.4. 选择存储引擎 14.5. 将存储引擎指定给表 14.6. 存储引擎和事务 14.7. 插入存储引擎 14.8. 拔出存储引擎 14.9. 插件式存储器的安全含义 15. 存储引擎和表类型 15.1. MyISAM存储引擎 15.1.1. MyISAM启动选项 15.1.2. 键所需的空间 15.1.3. MyISAM表的存储格式 15.1.4. MyISAM表方面的问题 15.2. InnoDB存储引擎 15.2.1. InnoDB概述 15.2.2. InnoDB联系信息 15.2.3. InnoDB配置 15.2.4. InnoDB启动选项 15.2.5. 创建InnoDB表空间 15.2.6. 创建InnoDB表 15.2.7. 添加和删除InnoDB数据和日志文件 15.2.8. InnoDB数据库的备份和恢复 15.2.9. 将InnoDB数据库移到另一台机器上 15.2.10. InnoDB事务模型和锁定 15.2.11. InnoDB性能调节提示 15.2.12. 多版本的实施 15.2.13. 表和索引结构 15.2.14. 文件空间管理和磁盘I/O 15.2.15. InnoDB错误处理 15.2.16. 对InnoDB表的限制 15.2.17. InnoDB故障诊断与排除 15.3. MERGE存储引擎 15.3.1. MERGE表方面的问题 15.4. MEMORY (HEAP)存储引擎 15.5. BDB (BerkeleyDB)存储引擎 15.5.1. BDB支持的操作系统 15.5.2. 安装BDB 15.5.3. BDB启动选项 15.5.4. BDB表的特性 15.5.5. 修改BDB所需的事宜 15.5.6. 对BDB表的限制 15.5.7. 使用BDB表时可能出现的错误 15.6. EXAMPLE存储引擎 15.7. FEDERATED存储引擎 15.7.1. 安装FEDERATED存储引擎 15.7.2. FEDERATED存储引擎介绍 15.7.3. 如何使用FEDERATED表 15.7.4. FEDERATED存储引擎的局限性 15.8. ARCHIVE存储引擎 15.9. CSV存储引擎 15.10. BLACKHOLE存储引擎 16. 编写自定义存储引擎 16.1. 前言 16.2. 概述 16.3. 创建存储引擎源文件 16.4. 创建handlerton 16.5. 对处理程序进行实例化处理 16.6. 定义表扩展 16.7. 创建表 16.8. 打开表 16.9. 实施基本的表扫描功能 16.9.1. 实施store_lock()函数 16.9.2. 实施external_lock()函数 16.9.3. 实施rnd_init()函数 16.9.4. 实施info()函数 16.9.5. 实施extra()函数 16.9.6. 实施rnd_next()函数 16.10. 关闭表 16.11. 为存储引擎添加对INSERT的支持 16.12. 为存储引擎添加对UPDATE的支持 16.13. 为存储引擎添加对DELETE的支持 16.14. API引用 16.14.1. bas_ext 16.14.2. close 16.14.3. create 16.14.4. delete_row 16.14.5. delete_table 16.14.6. external_lock 16.14.7. extra 16.14.8. info 16.14.9. open 16.14.10. rnd_init 16.14.11. rnd_next 16.14.12. store_lock 16.14.13. update_row 16.14.14. write_row 17. MySQL簇 17.1. MySQL簇概述 17.2. MySQL簇的基本概念 17.3. 多计算机的简单基础知识 17.3.1. 硬件、软件和联网 17.3.2. 安装 17.3.3. 配置 17.3.4. 首次启动 17.3.5. 加载示例数据并执行查询 17.3.6. 安全关闭和重启 17.4. MySQL簇的配置 17.4.1. 从源码创建MySQL簇 17.4.2. 安装软件 17.4.3. MySQL簇的快速测试设置 17.4.4. 配置文件 17.5. MySQL簇中的进程管理 17.5.1. 用于MySQL簇的MySQL服务器进程使用 17.5.2. ndbd,存储引擎节点进程 17.5.3. ndb_mgmd,“管理服务器”进程 17.5.4. ndb_mgm,“管理客户端”进程 17.5.5. 用于MySQL簇进程的命令选项 17.6. MySQL簇的管理 17.6.1. MySQL簇的启动阶段 17.6.2. “管理客户端”中的命令 17.6.3. MySQL簇中生成的事件报告 17.6.4. 单用户模式 17.6.5. MySQL簇的联机备份 17.7. 使用与MySQL簇的高速互连 17.7.1. 配置MySQL簇以使用SCI套接字 17.7.2. 理解簇互连的影响 17.8. MySQL簇的已知限制 17.9. MySQL簇发展的重要历程 17.9.1. MySQL 5.0中的MySQL簇变化 17.9.2. 关于MySQL簇的MySQL 5.1发展历程 17.10. MySQL簇常见问题解答 17.11. MySQL簇术语表 18. 分区 18.1. MySQL中的分区概述 18.2. 分区类型 18.2.1. RANGE分区 18.2.2. LIST分区 18.2.3. HASH分区 18.2.4. KEY分区 18.2.5. 子分区 18.2.6. MySQL分区处理NULL值的方式 18.3. 分区管理 18.3.1. RANGE和LIST分区的管理 18.3.2. HASH和KEY分区的管理 18.3.3. 分区维护 18.3.4. 获取关于分区的信息 19. MySQL中的空间扩展 19.1. 前言 19.2. OpenGIS几何模型 19.2.1. Geometry类的层次 19.2.2. 类Geometry 19.2.3. 类Point 19.2.4. 类Curve 19.2.5. 类LineString 19.2.6. 类Surface 19.2.7. 类Polygon 19.2.8. 类GeometryCollection 19.2.9. 类MultiPoint 19.2.10. 类MultiCurve 19.2.11. 类MultiLineString 19.2.12. 类MultiSurface 19.2.13. 类MultiPolygon 19.3. 支持的空间数据格式 19.3.1. 著名的文本(WKT)格式 19.3.2. 著名的二进制(WKB)格式 19.4. 创建具备空间功能的MySQL数据库 19.4.1. MySQL空间数据类型 19.4.2. 创建空间值 19.4.3. 创建空间列 19.4.4. 填充空间列 19.4.5. 获取空间数据 19.5. 分析空间信息 19.5.1. Geometry格式转换函数 19.5.2. Geometry函数 19.5.3. 从已有Geometry创建新Geometry的函数 19.5.4. 测试几何对象间空间关系的函数 19.5.5. 关于几何最小边界矩形(MBR)的关系 19.5.6. 测试几何类之间空间关系的函数 19.6. 优化空间分析 19.6.1. 创建空间索引 19.6.2. 使用空间索引 19.7. MySQL的一致性和兼容性 19.7.1. 尚未实施的GIS特性 20. 存储程序和函数 20.1. 存储程序和授权表 20.2. 存储程序的语法 20.2.1. CREATE PROCEDURE和CREATE FUNCTION 20.2.2. ALTER PROCEDURE和ALTER FUNCTION 20.2.3. DROP PROCEDURE和DROP FUNCTION 20.2.4. SHOW CREATE PROCEDURE和SHOW CREATE FUNCTION 20.2.5. SHOW PROCEDURE STATUS和SHOW FUNCTION STATUS 20.2.6. CALL语句 20.2.7. BEGIN ... END复合语句 20.2.8. DECLARE语句 20.2.9. 存储程序中的变量 20.2.10. 条件和处理程序 20.2.11. 光标 20.2.12. 流程控制构造 20.3. 存储程序、函数、触发程序和复制:常见问题 20.4. 存储子程序和触发程序的二进制日志功能 21. 触发程序 21.1. CREATE TRIGGER语法 21.2. DROP TRIGGER语法 21.3. 使用触发程序 22. 视图 22.1. ALTER VIEW语法 22.2. CREATE VIEW语法 22.3. DROP VIEW语法 22.4. SHOW CREATE VIEW语法 23. INFORMATION_SCHEMA信息数据库 23.1. INFORMATION_SCHEMA表 23.1.1. INFORMATION_SCHEMA SCHEMATA表 23.1.2. INFORMATION_SCHEMA TABLES表 23.1.3. INFORMATION_SCHEMA COLUMNS表 23.1.4. INFORMATION_SCHEMA STATISTICS表 23.1.5. INFORMATION_SCHEMA USER_PRIVILEGES表 23.1.6. INFORMATION_SCHEMA SCHEMA_PRIVILEGES表 23.1.7. INFORMATION_SCHEMA TABLE_PRIVILEGES表 23.1.8. INFORMATION_SCHEMA COLUMN_PRIVILEGES表 23.1.9. INFORMATION_SCHEMA CHARACTER_SETS表 23.1.10. INFORMATION_SCHEMA COLLATIONS表 23.1.11. INFORMATION_SCHEMA COLLATION_CHARACTER_SET_APPLICABILITY表 23.1.12. INFORMATION_SCHEMA TABLE_CONSTRAINTS表 23.1.13. INFORMATION_SCHEMA KEY_COLUMN_USAGE表 23.1.14. INFORMATION_SCHEMA ROUTINES表 23.1.15. INFORMATION_SCHEMA VIEWS表 23.1.16. INFORMATION_SCHEMA TRIGGERS表 23.1.17. 其他INFORMATION_SCHEMA表 23.2. SHOW语句的扩展 24. 精度数学 24.1. 数值的类型 24.2. DECIMAL数据类型更改 24.3. 表达式处理 24.4. 四舍五入 24.5. 精度数学示例 25. API和库 25.1. libmysqld,嵌入式MySQL服务器库 25.1.1. 嵌入式MySQL服务器库概述 25.1.2. 使用libmysqld编译程序 25.1.3. 使用嵌入式MySQL服务器时的限制 25.1.4. 与嵌入式服务器一起使用的选项 25.1.5. 嵌入式服务器中尚需完成的事项(TODO) 25.1.6. 嵌入式服务器示例 25.1.7. 嵌入式服务器的许可 25.2. MySQL C API 25.2.1. C API数据类型 25.2.2. C API函数概述 25.2.3. C API函数描述 25.2.4. C API预处理语句 25.2.5. C API预处理语句的数据类型 25.2.6. C API预处理语句函数概述 25.2.7. C API预处理语句函数描述 25.2.8. C API预处理语句方面的问题 25.2.9. 多查询执行的C API处理 25.2.10. 日期和时间值的C API处理 25.2.11. C API线程函数介绍 25.2.12. C API嵌入式服务器函数介绍 25.2.13. 使用C API时的常见问题 25.2.14. 创建客户端程序 25.2.15. 如何生成线程式客户端 25.3. MySQL PHP API 25.3.1. 使用MySQL和PHP的常见问题 25.4. MySQL Perl API 25.5. MySQL C++ API 25.5.1. Borland C++ 25.6. MySQL Python API 25.7. MySQL Tcl API 25.8. MySQL Eiffel Wrapper 25.9. MySQL程序开发实用工具 25.9.1. msql2mysql:转换mSQL程序以用于MySQL 25.9.2. mysql_config:获取编译客户端的编译选项 26. 连接器 26.1. MySQL Connector/ODBC 26.1.1. MyODBC介绍 26.1.2. 关于ODBC和MyODBC的一般信息 26.1.3. 如何安装MyODBC 26.1.4. 在Windows平台上从二进制版本安装MyODBC 26.1.5. I在Unix平台上从二进制版本安装MyODBC 26.1.6. 在Windows平台上从源码版本安装MyODBC 26.1.7. 在Unix平台上从源码版本安装MyODBC 26.1.8. 从BitKeeper开发源码树安装MyODBC 26.1.9. MyODBC配置 26.1.10. 与MyODBC连接相关的事宜 26.1.11. MyODBC和Microsoft Access 26.1.12. MyODBC和Microsoft VBA及ASP 26.1.13. MyODBC和第三方ODBC工具 26.1.14. MyODBC通用功能 26.1.15. 基本的MyODBC应用步骤 26.1.16. MyODBC API引用 26.1.17. MyODBC数据类型 26.1.18. MyODBC错误代码 26.1.19. MyODBC与VB:ADO、DAO和RDO 26.1.20. MyODBC与Microsoft.NET 26.1.21. 感谢 26.2. MySQL Connector/NET 26.2.1. 前言 26.2.2. 下载并安装MySQL Connector/NET 26.2.3. Connector/NET体系结构 26.2.4. 使用MySQL Connector/NET 26.2.5. MySQL Connector/NET变更史 26.3. MySQL Connector/J 26.3.1. 基本的JDBC概念 26.3.2. 安装 Connector/J 26.3.3. JDBC引用 26.3.4. 与J2EE和其他Java框架一起使用 Connector/J 26.3.5. 诊断 Connector/J方面的问题 26.3.6. Changelog 26.4. MySQL Connector/MXJ 26.4.1. 前言 26.4.2. 支持平台: 26.4.3. Junit测试要求 26.4.4. 运行Junit测试 26.4.5. 作为JDBC驱动程序的一部分运行 26.4.6. 在Java对象中运行 26.4.7. MysqldResource API 26.4.8. 在JMX代理(custom)中运行 26.4.9. 部署在标准的JMX代理环境下 (JBoss) 26.4.10. 安装 27. 扩展MySQL 27.1. MySQL内部控件 27.1.1. MySQL线程 27.1.2. MySQL测试套件 27.2. 为MySQL添加新函数 27.2.1. 自定义函数接口的特性 27.2.2. CREATE FUNCTION/DROP FUNCTION语法 27.2.3. 添加新的自定义函数 27.2.4. 添加新的固有函数 27.3. 为MySQL添加新步骤 27.3.1. 步骤分析 27.3.2. 编写步骤 A. 问题和常见错误 A.1. 如何确定导致问题的原因 A.2. 使用MySQL程序时的常见错误 A.2.1. 拒绝访问 A.2.2. 无法连接到[local] MySQL服务器 A.2.3. 客户端不支持鉴定协议 A.2.4. 输入密码时出现密码错误 A.2.5. 主机的host_name被屏蔽 A.2.6. 连接数过多 A.2.7. 内存溢出 A.2.8. MySQL服务器不可用 A.2.9. 信息包过大 A.2.10. 通信错误和失效连接 A.2.11. 表已满 A.2.12. 无法创建文件/写入文件 A.2.13. 命令不同步 A.2.14. 忽略用户 A.2.15. 表tbl_name不存在 A.2.16. 无法初始化字符集 A.2.17. 文件未找到 A.3. 与安装有关的事宜 A.3.1. 与MySQL客户端库的链接问题 A.3.2. 如何以普通用户身份运行MySQL A.3.3. 与文件许可有关的问题 A.4. 与管理有关的事宜 A.4.1. 如何复位根用户密码 A.4.2. 如果MySQL依然崩溃,应作些什么 A.4.3. MySQL处理磁盘满的方式 A.4.4. MySQL将临时文件储存在哪里 A.4.5. 如何保护或更改MySQL套接字文件/tmp/mysql.sock A.4.6. 时区问题 A.5. 与查询有关的事宜 A.5.1. 搜索中的大小写敏感性 A.5.2. 使用DATE列方面的问题 A.5.3. 与NULL值有关的问题 A.5.4. 与列别名有关的问题 A.5.5. 非事务表回滚失败 A.5.6. 从相关表删除行 A.5.7. 解决与不匹配行有关的问题 A.5.8. 与浮点比较有关的问题 A.6. 与优化器有关的事宜 A.7. 与表定义有关的事宜 A.7.1. 与ALTER TABLE有关的问题 A.7.2. 如何更改表中的列顺序 A.7.3. TEMPORARY TABLE问题 A.8. MySQL中的已知事宜 A.8.1. MySQL中的打开事宜 B. 错误代码和消息 B.1. 服务器错误代码和消息 B.2. 客户端错误代码和消息 C. 感谢 C.1. MySQL AB处的开发人 C.2. MySQL贡献人 C.3. 资料员和译员 C.4. MySQL使用和包含的库 C.5. 支持MySQL的软件包 C.6. 用于创建MySQL的工具 C.7. MySQL支持人员 D. MySQL变更史 D.1. 5.1.x版中的变更情况(开发) D.1.1. 5.1.2版中的变更情况(尚未发布) D.1.2. 5.1.1版中的变更情况(尚未发布) D.2. MyODBC的变更情况 D.2.1. MyODBC 3.51.12的变更情况 D.2.2. MyODBC 3.51.11的变更情况 E. 移植到其他系统 E.1. 调试MySQL服务器 E.1.1. 针对调试编译MySQL E.1.2. 创建跟踪文件 E.1.3. 在gdb环境下调试mysqld E.1.4. 使用堆栈跟踪 E.1.5. 使用日志文件找出mysqld中的错误原因 E.1.6. 如果出现表崩溃,请生成测试案例 E.2. 调试MySQL客户端 E.3. DBUG软件包 E.4. 关于RTS线程的注释 E.5. 线程软件包之间的差异 F. 环境变量 G. MySQL正则表达式 H. MySQL中的限制 H.1. 联合的限制 I. 特性限制 I.1. 对存储子程序和触发程序的限制 I.2. 对服务器端光标的限制 I.3. 对子查询的限制 I.4. 对视图的限制 I.5. 对XA事务的限制 J. GNU通用公共许可 K. MySQL FLOSS许可例外 索引 图形清单 14.1. MySQL插件式存储引擎的体系结构 14.2. 存储引擎比较 16.1. MySQL体系结构 表格清单 26.1. 连接属性 26.2. 转换表 26.3. 用于ResultSet.getObject()的MySQL类型和Java类型 26.4. MySQL对Java编码名称的翻译 示例清单 26.1. 从DriverManager获得连接 26.2. 使用java.sql.Statement执行SELECT查询 26.3. 存储程序示例 26.4. 使用Connection.prepareCall() 26.5. 注册输出参数 26.6. 设置CallableStatement输入参数 26.7. 检索结果和输出参数值 26.8. 使用Statement.getGeneratedKeys()检索AUTO_INCREMENT列的值 26.9. 使用SELECT LAST_INSERT_ID()检索AUTO_INCREMENT列的值 26.10. 在可更新的ResultSets中检索AUTO_INCREMENT列的值 26.11. 设置Unix环境下的CLASSPATH 26.12. 与J2EE应用服务器一起使用连接池 26.13. 重试逻辑的事务示例

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

morris131

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值