mysql> explain select id, sum(moneys) from sales2 group by id\G; **************************** 1. row ************************************* id: 1 select_type: SIMPLE table: sales2 type: ALL possible_keys: NULL key: NULL key_len: NULL ref: NULL rows: 1000 Extra: Using temporary; Using filesort 1 row in set(0.00 sec)
mysql> explain select id, sum(moneys) from sales2 group by id order by null\G; **************************** 1. row ************************************* id: 1 select_type: SIMPLE table: sales2 type: ALL possible_keys: NULL key: NULL key_len: NULL ref: NULL rows: 1000 Extra: Using temporary
从上面的例子可以看出第一个 SQL 语句需要进行“filesort”,而第二个 SQL 由于 ORDER BY NULL 不需要进行“filesort”,而 filesort 往往非常耗费时间。
优化 ORDER BY 语句
在某些情况中,MySQL 可以使用一个索引来满足 ORDER BY 子句,而不需要额外的排序。WHERE 条件和 ORDER BY 使用相同的索引,并且 ORDER BY 的顺序和索引顺序相同,并且 ORDER BY 的字段都是升序或者都是降序。
例如,下列 SQL 可以使用索引:
1 2 3
SELECT * FROM t1 ORDER BY key_part1,key_part2,...; SELECT * FROM t1 WHERE key_part1=1 ORDER BY key_part1 DESC, key_part2 DESC; SELECT * FROM t1 ORDER BY key_part1 DESC, key_part2 DESC;
但是在以下几种情况下则不使用索引:
1 2 3
SELECT * FROM t1 ORDER BY key_part1 DESC, key_part2 ASC; --order by 的字段混合 ASC 和 DESC SELECT * FROM t1 WHERE key2=constant ORDER BY key1; --用于查询行的关键字与 ORDER BY 中所使用的不相同 SELECT * FROM t1 ORDER BY key1, key2; --对不同的关键字使用 ORDER BY
优化嵌套查询
MySQL 4.1 开始支持 SQL 的子查询。这个技术可以使用 SELECT 语句来创建一个单列的查询结果,然后把这个结果作为过滤条件用在另一个查询中。使用子查询可以一次性地完成很多逻辑上需要多个步骤才能完成的 SQL 操作,同时也可以避免事务或者表锁死,并且写起来也很容易。但是,有些情况下,子查询可以被更有效率的连接(JOIN)替代。
mysql> explain select * from company2 where name like '%3'\G; **************************** 1. row ************************************* id: 1 select_type: SIMPLE table: company2 type: ALL possible_keys: NULL key: NULL key_len: NULL ref: NULL rows: 1000 Extra: Using where 1 row in set(0.00 sec)
mysql> explain select * from company2 where name like '3%'\G; **************************** 1. row ************************************* id: 1 select_type: SIMPLE table: company2 type: range possible_keys: ind_company2_name key: ind_company2_name key_len: 11 ref: NULL rows: 103 Extra: Using where 1 row in set(0.00 sec)
(4)如果列名是索引,使用 column_name is null 将使用索引。如下例中查询 name 为 null 的记录就用到了索引:
1 2 3 4 5 6 7 8 9 10 11 12 13
mysql> explain select * from company2 where name is null\G; **************************** 1. row ************************************* id: 1 select_type: SIMPLE table: company2 type: ref possible_keys: ind_company2_name key: ind_company2_name key_len: 11 ref: const rows: 1 Extra: Using where 1 row in set(0.00 sec)
存在索引但不使用索引
在下列情况下,虽然存在索引,但是 MySQL 并不会使用相应的索引。
(1)如果 MySQL 估计使用索引比全表扫描更慢,则不使用索引。例如如果列 key_part1 均匀分布在 1 和 100 之间,下列查询中使用索引就不是很好:
1
SELECT * FROM table_name where key_part1 > 1 and key_part1 < 90;
(2)如果使用 MEMORY/HEAP 表并且 where 条件中不使用“=”进行索引列,那么不会用到索引。heap 表只有在“=”的条件下才会使用索引。
(3)用 or 分割开的条件,如果 or 前的条件中的列有索引,而后面的列中没有索引,那么涉及到的索引都不会被用到,例如:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
mysql> show index from sales\G; **************************** 1. row ************************************* Table: sales Non_unique: 1 Key_name: ind_sales_year Seq_in_index: 1 Column_name: year Collation: A Cardinality: NULL Sub_part: NULL Packed: NULL Null: Index_type: BTREE Comment: 1 row in set(0.00 sec)
从上面可以发现只有 year 列上面有索引,来看如下的执行计划:
1 2 3 4 5 6 7 8 9 10 11 12 13
mysql> explain select * from sales where year = 2001 or country = 'China'\G; **************************** 1. row ************************************* id: 1 select_type: SIMPLE table: sales type: ALL possible_keys: ind_sales_year key: NULL key_len: NULL ref: NULL rows: 12 Extra: Using where 1 row in set(0.00 sec)
可见虽然在 year 这个列上存在索引 ind_sales_year,但是这个 SQL 语句并没有用到这个索引,原因就是 or 中有一个条件中的列没有索引。
(4)如果不是索引列的第一部分,如下例子:
1 2 3 4 5 6 7 8 9 10 11 12 13
mysql> explain select * from sales2 where moneys = 1\G; **************************** 1. row ************************************* id: 1 select_type: SIMPLE table: sales2 type: ALL possible_keys: NULL key: NULL key_len: NULL ref: NULL rows: 1000 Extra: Using where 1 row in set(0.00 sec)
可见虽然在 money 上面建有复合索引,但是由于 money 不是索引的第一列,那么在查询中这个索引也不会被 MySQL 采用。
(5)如果 like 是以 % 开始,例如:
1 2 3 4 5 6 7 8 9 10 11 12 13
mysql> explain select * from company2 where name like '%3'\G; **************************** 1. row ************************************* id: 1 select_type: SIMPLE table: company2 type: ALL possible_keys: NULL key: NULL key_len: NULL ref: NULL rows: 1000 Extra: Using where 1 row in set(0.00 sec)
可见虽然在 name 上建有索引,但是由于 where 条件中 like 的值的“%”在第一位了,那么 MySQL 也不会采用这个索引。
(6)如果列类型是字符串,那么一定记得在 where 条件中把字符常量值用引号引起来,否则的话即便这个列上有索引,MySQL 也不会用到的,因为,MySQL 默认把输入的常量值进行转换以后才进行检索。如下面的例子中 company2 表中的 name 字段是字符型的,但是 SQL 语句中的条件值 294 是一个数值型值,因此即便在 name 上有索引,MySQL 也不能正确地用上索引,而是继续进行全表扫描。
MySQL 客户端连接成功后,通过 show[session|global] status 命令可以提供服务器状态信息,也可以在操作系统上使用 mysqladmin extended-status 命令获得这些消息。show[session|global] status 可以根据需要加上参数“session”或者“global”来显示 session 级(当前连接)的统计结果和 global 级(自数据库上次启动至今)的统计结果。如果不写,默认使用参数是“session”。
插件式存储引擎是 MySQL 数据库最重要的特性之一,用户可以根据应用的需要选择如何存储和索引数据、是否使用事务等。MySQL 默认支持多种存储引擎,以适用于不同领域的数据库应用需要,用户可以通过选择使用不同的存储引擎提高应用的效率,提供灵活的存储,用户甚至可以按照自己的需要定制和使用自己的存储引擎,以实现最大程度的可定制性。
MySQL 5.0 支持的存储引擎包括 MyISAM、InnoDB、BDB、MEMORY、MERGE、EXAMPLE、NDB Cluster、ARCHIVE、CSV、BLACKHOLE、FEDERATED 等,其中 InnoDB 和 BDB 提供事务安全表,其它存储引擎都是非事务安全表。
特性
下面列出几种常见的存储引擎,并对比之间的区别。
特点
MyISAM
InnoDB
MEMORY
MERGE
NDB
存储限制
有
64TB
有
没有
有
事务安全
支持
锁机制
表锁
行锁
表锁
表锁
行锁
B 树索引
支持
支持
支持
支持
支持
哈希索引
支持
支持
全文索引
支持
集群索引
支持
数据缓存
支持
支持
支持
索引缓存
支持
支持
支持
支持
支持
数据可压缩
支持
空间使用
低
高
N/A
低
低
内存使用
低
高
中等
低
高
批量插入的速度
高
低
高
高
高
支持外键
支持
本文重点介绍最常遇到的两种存储引擎:MyISAM 和 InnoDB。
MyISAM
MyISAM 是 MySQL 的默认存储引擎。MyISAM 不支持事务、也不支持外键,其优势是访问的速度快,对事务完整性没有要求或者以 SELECT、INSERT 为主的应用基本上都可以使用这个引擎来创建表。