MySQL执行计划
EXPLAIN语句可以用作DESCRIBE的一个同义词,或获得关于MySQL如何执行SELECT语句的信息:EXPLAIN tbl_name是DESCRIBE tbl_name或SHOW COLUMNS FROM tbl_name的一个同义词。
· 如果在SELECT语句前放上关键词EXPLAIN,MySQL将解释它如何处理SELECT,提供有关表如何联接和联接的次序。
借助于EXPLAIN,可以知道什么时候必须为表加入索引以得到一个使用索引来寻找记录的更快的SELECT。还可以知道优化器是否以一个最佳次序联接表。为了强制优化器让一个SELECT语句按照表命名顺序的联接次序,语句应以STRAIGHT_JOIN而不只是SELECT开头。
查看执行计划,可以分析SQL合理地使用存在的索引,或调整当前的索引。
语法:
explain <sql语句> 或者 explain [extended] <sql语句> 或 explain partitions <sql语句>
EXPLAIN为用于SELECT语句中的每个表返回一行信息。表以它们在处理查询过程中将被MySQL读入的顺序被列出。MySQL用一遍扫描多次联接(single-sweep multi-join)的方式解决所有联接。这意味着MySQL从第一个表中读一行,然后找到在第二个表中的一个匹配行,然后在第3个表中等等。当所有的表处理完后,它输出选中的列并且返回表清单直到找到一个有更多的匹配行的表。从该表读入下一行并继续处理下一个表。
当使用EXTENDED关键字时,EXPLAIN产生附加信息,用于将执行计划‘反编译’成SQL语句,运行show warnings 可等到优化后的查询语句,包括优化器限定SELECT语句中的表和列名,重写并且执行优化规则后SELECT语句是什么样子,并且还可能包括优化过程的其它注解。
Partitions用于分区表的执行计划。
注:也可以使用desc命令来查看执行计划,用法desc <sql语句>
mysql> explain select * from order_item;
+----+-------------+------------+------+---------------+------+---------+------+------+-------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+------------+------+---------------+------+---------+------+------+-------+
| 1 | SIMPLE | order_item | ALL | NULL | NULL | NULL | NULL | 4553 | |
+----+-------------+------------+------+---------------+------+---------+------+------+-------+
1 row in set (0.00 sec)
mysql> desc select * from order_item;
+----+-------------+------------+------+---------------+------+---------+------+------+-------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+------------+------+---------------+------+---------+------+------+-------+
| 1 | SIMPLE | order_item | ALL | NULL | NULL | NULL | NULL | 4553 | |
+----+-------------+------------+------+---------------+------+---------+------+------+-------+
1 row in set (0.02 sec)
EXPLAIN的每个输出行提供一个表的相关信息,并且每个行包括下面的列:
• id SELECT识别符。这是SELECT的查询序列号。
例:
mysql> explain select * from (select * from (select * from tb where id = 4) a) b;
+----+-------------+------------+--------+---------------+---------+---------+------+------+-------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+------------+--------+---------------+---------+---------+------+------+-------+
| 1 | PRIMARY | <derived2> | system | NULL | NULL | NULL | NULL | 1 | |
| 2 | DERIVED | <derived3> | system | NULL | NULL | NULL | NULL | 1 | |
| 3 | DERIVED | tb | const | PRIMARY | PRIMARY | 4 | | 1 | |
+----+-------------+------------+--------+---------------+---------+---------+------+------+-------+
3 rows in set (0.59 sec)
这条SQL的执行顺序是从里向外的执行,就是从id=3 向上执行。说明:对于子查询,id的序号会递增,id值越大优先级越高,越先被执行
mysql> explain select s.id, s.sname from student s, sc, course c where s.id=sc.sid and sc.cid = c.id and c.tid = '1001';
+----+-------------+-------+--------+---------------+---------+---------+---------------+------+-------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+-------+--------+---------------+---------+---------+---------------+------+-------------+
| 1 | SIMPLE | s | ALL | PRIMARY | NULL | NULL | NULL | 1 | |
| 1 | SIMPLE | sc | ref | sid,cid | sid | 5 | testdb.s.id | 1 | Using where |
| 1 | SIMPLE | c | eq_ref | PRIMARY,tid | PRIMARY | 4 | testdb.sc.cid | 1 | Using where |
+----+-------------+-------+--------+---------------+---------+---------+---------------+------+-------------+
3 rows in set (0.00 sec)
这条SQL的执行顺序是从左到右,说明:id相同时,执行顺序由上至下
id如果相同,可以认为是一组,从上往下顺序执行;在所有组中,id值越大,优先级越高,越先执行
• select_type SELECT类型,可以为以下任何一种:
o SIMPLE 简单SELECT(不含UNION或子查询)
o PRIMARY 子查询中的最外层查询,(不是主键查询)
o UNION UNION中的第二个或后面的SELECT语句(第一个SELECT 为PRIMARY)
o DEPENDENT UNION UNION中的第二个或后面的SELECT语句,取决于外面的查询
o UNION RESULT UNION的结果。
o SUBQUERY 子查询中的第一个SELECT,结果不依赖于外部查询结果集;
o DEPENDENT SUBQUERY 子查询中的第一个SELECT,取决于外面的查询
o DERIVED 导出表的SELECT(FROM子句的子查询)
• table 输出的行所引用的表。
• type 联接类型,表示MySQL在表中找到所需行的方式,又称“访问类型”。下面给出各种联接类型,按照从最佳类型到最坏类型进行排序:
常见类型如下:
由左至右,性能由最差到最好
o NULL MySQL在优化过程中分解语句,执行时甚至不用访问表域索引。
o system 表仅有一行(=系统表)。这是const联接类型的一个特例。
o const 读常量,且最多只会有一条记录匹配。const表很快,因为它们只读取一次!
const可用于常数值比较PRIMARY KEY或UNIQUE索引的所有部分。例:在下面的查询中,tbl_name可以用于const表:
SELECT * from tbl_name WHERE primary_key=1;
SELECT * from tbl_name WHERE primary_key_part1=1和 primary_key_part2=2;
例:
mysql> explain select * from student where id=1001;
+----+-------------+---------+-------+---------------+---------+---------+-------+------+-------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+---------+-------+---------------+---------+---------+-------+------+-------+
| 1 | SIMPLE | student | const | PRIMARY | PRIMARY | 4 | const | 1 | |
+----+-------------+---------+-------+---------------+---------+---------+-------+------+-------+
1 row in set (0.00 sec)
主键位于Where列表中,MySQL将该查询转换为一个常量。例:
或mysql> explain select * from (select * from student where id=1001) t;
+----+-------------+------------+--------+---------------+---------+---------+------+------+-------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+------------+--------+---------------+---------+---------+------+------+-------+
| 1 | PRIMARY | <derived2> | system | NULL | NULL | NULL | NULL | 1 | |
| 2 | DERIVED | student | const | PRIMARY | PRIMARY | 4 | | 1 | |
+----+-------------+------------+--------+---------------+---------+---------+------+------+-------+
2 rows in set (0.00 sec)
o eq_ref (唯一性索引扫描) 最多只会有一条匹配结果,一般是通过主键或者唯一键索引来访问; eq_ref可以用于使用= 操作符比较的带索引的列。比较值可以为常量或一个使用在该表前面所读取的表的列的表达式。
例:在下面的例子中,MySQL可以使用eq_ref联接来处理ref_tables:
SELECT * FROM ref_table, other_table WHERE ref_table.key_column=other_table.column;
SELECT * FROM ref_table, other_table WHERE ref_table.key_column_part1=other_table.column AND ref_table.key_column_part2=1;
例:
mysql> explain select * from teacher t, teacher t1 where t.id = t1.id; --唯一性索引扫描,对于每个索引键,表中只有一条记录与之匹配。常见于主键或唯一索引扫描
+----+-------------+-------+--------+---------------+---------+---------+-------------+------+-------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+-------+--------+---------------+---------+---------+-------------+------+-------+
| 1 | SIMPLE | t | ALL | PRIMARY | NULL | NULL | NULL | 1 | |
| 1 | SIMPLE | t1 | eq_ref | PRIMARY | PRIMARY | 4 | testdb.t.id | 1 | |
+----+-------------+-------+--------+---------------+---------+---------+-------------+------+-------+
2 rows in set (0.00 sec)
o ref (非唯一性索引扫描) 返回匹配某个单独值的所有行,常见于使用非唯一索引或唯一索引的非唯一前缀进行的查找
Join 语句中被驱动表索引引用查询:对于每个来自于前面的表的行组合,所有有匹配索引值的行将从这张表中读取。如果联接只使用键的最左边的前缀,或如果键不是UNIQUE或PRIMARY KEY(换句话说,如果联接不能基于关键字选择单个行的话),则使用ref。如果使用的键仅仅匹配少量行,该联接类型是不错的。ref可以用于使用=或<=>操作符的带索引的列。
例:在下面的例子中,MySQL可以使用ref联接来处理ref_tables:
SELECT * FROM ref_table WHERE key_column=expr;
SELECT * FROM ref_table, other_table WHERE ref_table.key_column=other_table.column;
SELECT * FROM ref_table,other_table WHERE ref_table.key_column_part1=other_table.column AND ref_table.key_column_part2=1;
例:
mysql> select * from teacher t, course c where t.id=c.tid;
+------+-------+------+---------+------+
| id | tname | id | cname | tid |
+------+-------+------+---------+------+
| 2010 | wang | 1011 | english | 2010 |
+------+-------+------+---------+------+
1 row in set (0.00 sec)
mysql>
mysql> explain select * from teacher t, course c where t.id=c.tid; --非唯一性索引扫描,返回匹配某个单独值的所有行。常见于使用非唯一索引即唯一索引的非唯一前缀进行的查找
+----+-------------+-------+------+---------------+------+---------+-------------+------+-------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+-------+------+---------------+------+---------+-------------+------+-------------+
| 1 | SIMPLE | t | ALL | PRIMARY | NULL | NULL | NULL | 1 | |
| 1 | SIMPLE | c | ref | tid | tid | 5 | testdb.t.id | 1 | Using where |
+----+-------------+-------+------+---------------+------+---------+-------------+------+-------------+
2 rows in set (0.00 sec)
o ref_or_null 该联接类型如同ref,但是添加了MySQL可以专门搜索包含NULL值的行。在解决子查询中经常使用该联接类型的优化。与ref 唯一区别就是在使用索引引用查询之外再增加一个空值的查询;参见7.2.7节,“MySQL如何优化IS NULL”。
例:在下面的例子中,MySQL可以使用ref_or_null联接来处理ref_tables:
SELECT * FROM ref_table WHERE key_column=expr OR key_column IS NULL;
o index_merge 查询中同时使用两个(或更多)索引,然后对索引结果进行merge 之后再读取表数据。在这种情况下,key列包含了使用的索引的清单,key_len包含了使用的索引的最长的关键元素。详细信息参见7.2.6节,“索引合并优化”。
o unique_subquery 子查询中的返回结果字段组合是主键或者唯一约束。该类型替换了下面形式的IN子查询的ref:
value IN (SELECT primary_key FROM single_table WHERE some_expr)
unique_subquery是一个索引查找函数,可以完全替换子查询,效率更高。
o index_subquery 子查询中的返回结果字段组合是一个索引(或索引组合),但不是一个主键或者唯一索引。该联接类型类似于unique_subquery,可以替换IN子查询,但只适合下列形式的子查询中的非唯一索引:
value IN (SELECT key_column FROM single_table WHERE some_expr)
o range (索引范围扫描) :只检索给定范围的行,使用一个索引来选择行。key列显示使用了哪个索引。key_len包含所使用索引的最长关键元素。在该类型中ref列为NULL。当使用=、<>、>、>=、<、<=、IS NULL、<=>、BETWEEN或者IN操作符,用常量比较关键字列时,可以使用range:
例: SELECT * FROM tbl_name WHERE key_column = 10;
SELECT * FROM tbl_name WHERE key_column BETWEEN 10 and 20;
SELECT * FROM tbl_name WHERE key_column IN (10,20,30);
SELECT * FROM tbl_name WHERE key_part1= 10 AND key_part2 IN (10,20,30);
例:
mysql> explain select * from course where tid between 2000 and 3000; --索引范围扫描,对索引的扫描开始于某一点,返回匹配值域的行,常见于between、<、>等的查询
+----+-------------+--------+-------+---------------+------+---------+------+------+-------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+--------+-------+---------------+------+---------+------+------+-------------+
| 1 | SIMPLE | course | range | tid | tid | 5 | NULL | 1 | Using where |
+----+-------------+--------+-------+---------------+------+---------+------+------+-------------+
1 row in set (0.00 sec)
注意,在对主键使用between 或in 等查询时,也可能是:
mysql> explain select * from teacher where id between 2000 and 3000;
+----+-------------+---------+-------+---------------+-------+---------+------+------+--------------------------+
| id | select_type | table | type | possible_keys | key | key_len | ref |rows | Extra |
+----+-------------+---------+-------+---------------+-------+---------+------+------+--------------------------+
| 1 | SIMPLE | teacher | index | PRIMARY | tname | 43 | NULL | 1 | Using where; Using index |
+----+-------------+---------+-------+---------------+-------+---------+------+------+--------------------------+
1 row in set (0.00 sec)
mysql> explain select * from teacher where id in (2000, 3000);
+----+-------------+---------+-------+---------------+-------+---------+------+------+--------------------------+
| id | select_type | table | type | possible_keys | key | key_len | ref |rows | Extra |
+----+-------------+---------+-------+---------------+-------+---------+------+------+--------------------------+
| 1 | SIMPLE | teacher | index | PRIMARY | tname | 43 | NULL | 1 | Using where; Using index |
+----+-------------+---------+-------+---------------+-------+---------+------+------+--------------------------+
1 row in set (0.00 sec)
o index (全索引扫描) :该联接类型与ALL相同,除了只有索引树被扫描。这通常比ALL快,因为索引文件通常比数据文件小。当查询只使用作为单索引一部分的列时,MySQL可以使用该联接类型。
o ALL (全表扫描):对于每个来自于先前的表的行组合,进行完整的表扫描。如果表是第一个没标记const的表,这通常不好,并且通常在它情况下很差。通常可以增加更多的索引而不要使用ALL,使得行能基于前面的表中的常数值或列值被检索出。
• possible_keys 该查询可以利用的索引。 如果没有任何索引可以使用,就会显示成null,在这种情况下,可以通过检查WHERE子句看是否它引用某些列或适合索引的列来提高你的查询性能。如果是这样,创造一个适当的索引并且再次用EXPLAIN检查查询。参见13.1.2节,“ALTER TABLE语法”。
为了看清一张表有什么索引,使用SHOW INDEX FROM tbl_name。
• key key列显示MySQL实际从possible_keys 中所选择使用的键(索引)。如果没有选择索引,键是NULL。要想强制MySQL使用或忽视possible_keys列中的索引,在查询中使用FORCE INDEX、USE INDEX或者IGNORE INDEX。参见13.2.7节,“SELECT语法”。
对于MyISAM和BDB表,运行ANALYZE TABLE可以帮助优化器选择更好的索引。对于MyISAM表,可以使用myisamchk --analyze。参见13.5.2.1节,“ANALYZE TABLE语法”和5.9.4节,“表维护和崩溃恢复”。
• key_len 被选中使用索引的索引键长度。如果键是NULL,则长度为NULL。注意通过key_len值我们可以确定MySQL将实际使用一个多部关键字的几个部分。
例:
mysql> explain select cname from course; -- 没有利用到索引
+----+-------------+--------+------+---------------+------+---------+------+------+-------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+--------+------+---------------+------+---------+------+------+-------+
| 1 | SIMPLE | course | ALL | NULL | NULL | NULL | NULL |1 | |
+----+-------------+--------+------+---------------+------+---------+------+------+-------+
1 row in set (0.00 sec)
mysql> explain select * from course where tid = 2002; -- 这里存在一个外键索引
+----+-------------+--------+------+---------------+------+---------+-------+------+-------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+--------+------+---------------+------+---------+-------+------+-------------+
| 1 | SIMPLE | course | ref | tid | tid | 5 | const | 1 | Using where |
+----+-------------+--------+------+---------------+------+---------+-------+------+-------------+
1 row in set (0.00 sec)
key_len显示的值为索引字段的最大可能长度,并非实际使用长度,即key_len是根据表定义计算而得,不是通过表内检索出的
• ref 列出是通过常量(const),还是某个表的某个字段(如果是join)来过滤(通过key)的;
例:
mysql> explain select * from teacher t, course c where t.id=c.tid and c.cname='ac';
+----+-------------+-------+-------+---------------+-------+---------+-------------+------+-------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+-------+-------+---------------+-------+---------+-------------+------+-------------+
| 1 | SIMPLE | t | index | PRIMARY | tname | 43 | NULL | 1 | Using index |
| 1 | SIMPLE | c | ref | tid | tid | 5 | testdb.t.id | 1 | Using where |
+----+-------------+-------+-------+---------------+-------+---------+-------------+------+-------------+
2 rows in set (0.00 sec)
本例中,由key_len可知course表的tid被充分使用,course表的tid匹配teacher表的id,course表的cname匹配’ac’。
• rows rows列显示MySQL认为它执行查询时必须检查的行数。
• Extra 该列包含MySQL解决查询的详细信息。下面解释了该列可以显示的不同的文本字符串:
o Distinct MySQL找到了第一条匹配的结果后,将停止该值的查询而转为后面其他值的查询;
o Not exists MySQL能够对查询进行LEFT JOIN优化,发现1个匹配LEFT JOIN标准的行后,不再为前面的的行组合在该表内检查更多的行。
下面是一个可以这样优化的查询类型的例子:
SELECT * 从t1 LEFT JOIN t2 ON t1.id=t2.id WHERE t2.id IS NULL;
假定t2.id定义为NOT NULL。在这种情况下,MySQL使用t1.id的值扫描t1并查找t2中的行。如果MySQL在t2中发现一个匹配的行,它知道t2.id绝不会为NULL,并且不再扫描t2内有相同的id值的行。换句话说,对于t1的每个行,MySQL只需要在t2中查找一次,无论t2内实际有多少匹配的行。
o range checked for each record (index map: #) MySQL没有发现好的可以使用的索引,但发现如果来自前面的表的列值已知,可能部分索引可以使用。对前面的表的每个行组合,MySQL检查是否可以使用range或index_merge访问方法来索取行。关于适用性标准的描述参见7.2.5节,“范围优化”和7.2.6节,“索引合并优化”,不同的是前面表的所有列值已知并且认为是常量。这并不很快,但比执行没有索引的联接要快得多。
o Using filesort(使用文件排序) 当Query 中包含ORDER BY 操作,而且无法利用索引完成排序操作的时候,MySQL Query Optimizer 不得不选择相应的排序算法(文件排序)来实现。参见7.2.12节,“MySQL如何优化ORDER BY”。
o Using index(使用索引排序) 所需要的数据只需要在Index 即可全部获得而不需要再到表中取数据。当查询只使用作为单一索引一部分的列时,可以使用该策略。
例:
mysql> explain select * from teacher where tname like 'tom';
+----+-------------+---------+-------+---------------+-------+---------+------+------+--------------------------+
| id | select_type | table | type | possible_keys | key | key_len | ref |rows | Extra |
+----+-------------+---------+-------+---------------+-------+---------+------+------+--------------------------+
| 1 | SIMPLE | teacher | index | tname | tname | 43 | NULL | 1 | Using where; Using index |
+----+-------------+---------+-------+---------------+-------+---------+------+------+--------------------------+
1 row in set (0.00 sec)
如果是mysql> explain select id, tname from teacher where tname like 'tom';
+----+-------------+---------+-------+---------------+-------+---------+------+------+--------------------------+
| id | select_type | table | type | possible_keys | key | key_len | ref |rows | Extra |
+----+-------------+---------+-------+---------------+-------+---------+------+------+--------------------------+
| 1 | SIMPLE | teacher | index | tname | tname | 43 | NULL | 1 | Using where; Using index |
+----+-------------+---------+-------+---------------+-------+---------+------+------+--------------------------+
1 row in set (0.00 sec)
覆盖索引(Covering Index):MySQL可以利用索引返回select列表中的字段,而不必根据索引再次读取数据文件,包含所有满足查询需要的数据的索引称为 覆盖索引(Covering Index)
注意: 如果要使用覆盖索引,一定要注意select列表中只取出需要的列,不可select *,因为如果将所有字段一起做索引会导致索引文件过大,查询性能下降。
o Using temporary(使用临时表) 当MySQL 在某些操作中必须使用临时表的时候(使用临时表来存储结果集),在Extra 信息中就会出现Using temporary 。主要常见于GROUP BY 和ORDER BY (分组与排序)等操作中。
mysql> explain select * from course where id in (1000, 3000) group by cname;
+----+-------------+--------+-------+---------------+---------+---------+------+------+----------------------------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+--------+-------+---------------+---------+---------+------+------+----------------------------------+
| 1 | SIMPLE | course | range | PRIMARY | PRIMARY | 4 | NULL | 2 | Using where; Using temporary; Using filesort |
+----+-------------+--------+-------+---------------+---------+---------+------+------+---------------------------------+
1 row in set (0.00 sec)
注意的是,如果cname上存在索引,则结果就不一样了,如,在teacher表的tname存在唯一约束,故:
mysql> explain select * from teacher where id in (2000, 3000) group by tname;
+----+-------------+---------+-------+---------------+-------+---------+------+------+--------------------------+
| id | select_type | table | type | possible_keys | key | key_len | ref |rows | Extra |
+----+-------------+---------+-------+---------------+-------+---------+------+------+--------------------------+
| 1 | SIMPLE | teacher | index | PRIMARY | tname | 43 | NULL | 1 | Using where; Using index |
+----+-------------+---------+-------+---------------+-------+---------+------+------+--------------------------+
1 row in set (0.00 sec)
o Using where (使用子句过滤) 如果不是读取表的所有数据,或者不是仅仅通过索引就可以获取所有需要的数据,则会出现Using where 信息。如果想要使查询尽可能快,应找出Using filesort 和Using temporary的Extra值。
如果查询未能使用索引,Using where的作用只是提醒我们MySQL将用where子句来过滤结果集
mysql> explain select * from course where cname like 'english';
+----+-------------+--------+------+---------------+------+---------+------+------+-------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+--------+------+---------------+------+---------+------+------+-------------+
| 1 | SIMPLE | course | ALL | NULL | NULL | NULL | NULL |1 | Using where |
+----+-------------+--------+------+---------------+------+---------+------+------+-------------+
1 row in set (0.00 sec)
o Using sort_union(...), Using union(...), Using intersect(...) 这些函数说明如何为index_merge联接类型合并索引扫描。详细信息参见7.2.6节,“索引合并优化”。
o Using index for group-by 类似于访问表的Using index方式,Using index for group-by表示MySQL发现了一个索引,可以用来查询GROUP BY或DISTINCT查询的所有列,而不要额外搜索硬盘访问实际的表。并且,按最有效的方式使用索引,以便对于每个组,只读取少量索引条目。详情参见7.2.13节,“MySQL如何优化GROUP BY”。
通过相乘EXPLAIN输出的rows列的所有值,你能得到一个关于一个联接如何的提示。这应该粗略地告诉你MySQL必须检查多少行以执行查询。当你使用max_join_size变量限制查询时,也用这个乘积来确定执行哪个多表SELECT语句。参见7.5.2节,“调节服务器参数”。
MySQL执行计划的局限
• EXPLAIN不会告诉你关于触发器、存储过程的信息或用户自定义函数对查询的影响情况
• EXPLAIN不考虑各种Cache
• EXPLAIN不能显示MySQL在执行查询时所作的优化工作
• 部分统计信息是估算的,并非精确值
• EXPALIN只能解释SELECT操作,其他操作要重写为SELECT后查看执行计划
相关表:
mysql> show create table student\G;
*************************** 1. row ***************************
Table: student
Create Table: CREATE TABLE `student` (
`id` int(11) NOT NULL DEFAULT '0',
`sname` varchar(20) DEFAULT NULL,
`sex` varchar(2) DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=gbk
1 row in set (0.00 sec)
ERROR:
No query specified
mysql> show create table course\G;
*************************** 1. row ***************************
Table: course
Create Table: CREATE TABLE `course` (
`id` int(11) NOT NULL DEFAULT '0',
`cname` varchar(20) DEFAULT NULL,
`tid` int(11) DEFAULT NULL,
PRIMARY KEY (`id`),
KEY `tid` (`tid`),
CONSTRAINT `course_ibfk_1` FOREIGN KEY (`tid`) REFERENCES `teacher` (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=gbk
1 row in set (0.00 sec)
ERROR:
No query specified
mysql> show create table sc\G;
*************************** 1. row ***************************
Table: sc
Create Table: CREATE TABLE `sc` (
`sid` int(11) DEFAULT NULL,
`cid` int(11) DEFAULT NULL,
`score` int(11) DEFAULT NULL,
KEY `sid` (`sid`),
KEY `cid` (`cid`),
CONSTRAINT `sc_ibfk_1` FOREIGN KEY (`sid`) REFERENCES `student` (`id`),
CONSTRAINT `sc_ibfk_2` FOREIGN KEY (`cid`) REFERENCES `course` (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=gbk
1 row in set (0.00 sec)
ERROR:
No query specified
mysql> show create table teacher\G;
*************************** 1. row ***************************
Table: teacher
Create Table: CREATE TABLE `teacher` (
`id` int(11) NOT NULL DEFAULT '0',
`tname` varchar(20) DEFAULT NULL,
PRIMARY KEY (`id`),
UNIQUE KEY `tname` (`tname`)
) ENGINE=InnoDB DEFAULT CHARSET=gbk
1 row in set (0.00 sec)
ERROR:
No query specified
mysql> alter table teacher add unique(tname);
insert into teacher values(2010, 'wang');
insert into course values(1011, 'english', 2010);