18.2优化查询
査询是数据库中最频繁的操作。提高了查询速度可以有效的提高MySQL数据库的性能。本节将为读者介绍优化査询的方法。
18.2.1分析查询语句
通过对查洵语句的分析,可以了解查询语句的执行情况。MySQL中,可以使用EXPLAIN语句和DESCRIBE语句来分析查询语句。本小节将为读者介绍这两种分析查询 语句的方法。
EXPLAIN语句的基本语法如下:
EXPLAIN SELECT 语句;
通过EXPLAIN关键字可以分析后面的SELECT语句的执行情况。并且能够分析出所査询的表的一些内容。
【示例18-1】下面使用EXPLAIN语句来分析一个查询语句。代码执行如下:
mysql> EXPLAIN SELECT * FROM student \G id:1 select_type: SIMPLE table: student type: ALL possible_keys: NULL key: NULL key_len: NULL ref: NULL rows: 6 Extra: 1 row in set (0.01 sec)
查询结果显示了id、select_type>、table、type、possible_keys和key等信息。下面分別进行解释。
id:表示SELECT语句的编号
select_type:表示SELECT语句的类型。该参数有几个常用的取值,即SIMP;E表示简单查询,其中不包括连接查询和子查询;PRIMARY表示主查询,或者是最外层的査询语句;UNION表示连接查询的第二个或后面的查询语句;
table:表示查询的表
type:表示表的连接类型。该参数有几个常用的取值,即system表示表中只有一条记录;const表示表中有多条记录,但只从表中查询一条记录;ALL表示对表进行了完整的扫描;eq_ref表示多表连接时,后面的表使用了UNlQUE或者PRIMARY KEY;ref表示多表查询时,后面的表使用了普通索引;unique_subquery表示子查询中使用了UNlQUE或者PRIMARY KEY;index_subquery表示子查询中使用了普通索引;range表示查询语句中给出了查询范围;index表示对表中的索引进行了完整的扫描
possible_keys:表示查询中可能使用的索引
key:表示查询使用到的索引
key_len:表示索引字段的长度
ref:表示使用哪个列或常数与索引一起来查询记录
rows:表示查询的行数
Extra:表示查询过程的附件信息
DESCRIBE语句的使用方法与EXPLAIN语句是一样的。这两者的分析结果也是一样的。DESCRIBE语句的语法形式如下:
DESCRIBE SELECT 语句;
DESCRIBE可以缩写成DESC。
18.2.2 索引对查询速度的影响
索引可以快速的定位表中的某条记录。使用索引可以提高数据库查询的速度,从而提高数据库的性能。本小节将为读者介绍索引对查询速度的影响。 如果查询时不使用索引,查询语句将查询表中的所有字段。这样查询的速度会很慢。 如果使用索引进行查询,查询语句只查询索引字段。这样可以减少查询的记录数,达到提高查询速度的目的。
【示例18-2】下面是查询语句中不使用索引和使用索引的对比。现在分析未使用索引时的查询情况,EXPLAIN语句执行如下:
mysql> EXPLAIN SELECT * FROM student WHERE name='张三' \G ***********************1.row*********************** id:i select_type: SIMPLE table: student type: ALL possible_keys: NULL key: NULL key_len: NULL reT. NULL rows: 6 Extra: Using where 1 row in set(0.00 sec)
结果显示,rows参数的值为6。这说明这个查询语句查询了6条记录。现在在name字段上建立一个名为index_name的索引。CREATE语句执行如下:
现在,name字段上已经有索引了,然后再分析查询语句的执行情况。EXPLAIN语句执行如下:
mysql> EXPLAIN SELECT * FROM student WHERE name='张三' \G **************************1.row******************* id: 1 select_type: SIMPLE table: student type: ref possible_keys:index_name key:index_name key_len:22 ref:const Extra:Using where 1 row in set(0.00 sec)
结果显示,rows参数的值为1。这表示这个查询语句只查询了一条记录,其查询速度自然比查询6条记录快。而且possible_keys和key的值都是index_name,这说明查询时使用了index_name索引。
18.2.3使用索引查询
索引可以提高查询的速度。但是有些时候即使查询时使用的是索引,但索引并没有起作用。本小节将向读者介绍索引的使用。
1.查询语句中使用口LIKE关键字
在查询语句中使用LIKE关键字进行查询时,如果匹配字符串的第一个字符为“%” 时,索引不会被使用。如果“%”不是在第一个位置,索引就会被使用。
【示例18-3】下面查询语句中使用LIKE关键字,并且匹配的字符串中含有“%”符 号。EXPLAIN语句执行如下:
mysql> EXPLAIN SELECT * FROM student WHERE name LIKE,'%四' \G ************************1.row********************** id: 1 select_type: SIMPLE table: student type: ALL possible_keys: NULL key: NULL key_len: NULL ref: NULL rows: 6 Extra: Using where 1 row in set (0.00 sec) mysql> EXPLAIN SELECT * FROM student WHERE name LIKE '李%' \G ******************1. row *************************** select_type: SIMPLE table: student type: range possible_keys: index_name key: index_name key_len: 22 ref: NULL rows: 1 Extra: Using where 1 row in set (0.00 sec)
第一个查询语句执行后,rows参数的值为6,表示这次查询过程中查询了6条记录:第二个查询语句执行后,rows参数的值为l,表示这次查询过程只查询一条记录。同样是 使用的name字段进行查询,第一个查询语句没有使用索引,而第二个查洵语句使用了索引index_name。因为第一个查询语句的LIKE关键字后的字符串以“%”开头。
2. 查询语句中使用多列索引
多列索引是在表的多个字段上创建一个索引。只有査询条件中使用了这些字段中第一个字段时,索引才会被使用。
【示例18-4】下面在birth和department两个字段上创建多列索引,然后验证多列索引的使用情况。
mysql> CREATE INDEX index_birth_department ON student(birth,department); Query OK, 6 rows affected (0.01 sec) Records: 6 Duplicates: 0 Warnings: 0 mysql> EXPLAIN SELECT * FROM student WHERE birth=1991 \G *******************1. row *************************** id: 1 select_type: SIMPLE table: student type: ref possible_keys: index_birth_department key: index_birth_department key_len: 2 ref: const rows: 1 Extra: Using where 1 row in set (0.00 sec) mysql> EXPLAIN SELECT * FROM student WHERE department='英语系' \G ********************1.row****************** id: 1 select_type: SIMPLE table: student type: ALL possible_keys: NULL key: NULL key_len: NULL ref: NULL rows: 6 Extra: Using where 1 row in set (0.00 sec)
在birth字段和department字段上创建一个多列索引。第一个查询语句的查询条件使用了 birth字段,分析结果显示rows参数的值为1。而且显示查询过程中使用了index_birth_department索引。第二个査询语句的查询条件使用了department字段,结果显示rows参数的值为6。而且key参数的值为NULL,这说明第二个查询语句没有使用索引。因为name字段是多列索引的第一个字段,只有査询条件中使用 name字段才会使index_name_department 索引起作用。
3.查询语句中使用OR关键字
査询语句只有OR关键字时,如果OR前后的两个条件的列都是索引时,查询中将使用索引。如果OR前后有一个条件的列不是索引,那么査询中将不使用索引。
【示例18-5】下面演示OR关键字的使用。
mysql> EXPLAIN SELECT * FROM student WHERE name='张三' or sex='女' \G ****************1.row***************** id: 1 select_type: SIMPLE table: student type: ALL possible_keys: index_name key: NULL key_len: NULL ref: NULL rows: 6 Extra: Using where 1 row in set (0.00 sec) mysql> EXPLAIN SELECT * FROM student WHERE name='张三' or sex='女' \G ****************1.row***************** id: 1 select_type: SIMPLE table: student type: index_merge possible_keys: PRIMARY,id,index_name key: index_name,PRIMARY key_len: 22,4 ref: NULL rows: 2 Extra: Using union(index_name,PRIMARY); Using where row in set (0.00 sec)
第一个查询语句没有使用索引,因为sex字段上没有索引;第二个查询语句使用了index_name和PRIMARY这两个索引’因为name字段和id字段上都有索引。
技巧:使用索引查询记录时,一定要注意索引的使用情况。例如,LlKE关键字配置的字符串不能以“%”开头;使用多列索引时,查询条件必须要使用这个索引的第一个字段;使用or关键字时,or关键字连接的所有条件都必须使用索引。
18.2.4优化子查询
很多查询中需要使用子査询。子查询可以使查询语句很灵活,但子查询的执行效率不高。子查询时,MySQL需要为内层查询语句的查询结果建立一个临时表。然后外层查询语句再临时表中查询记录。査询完毕后,MySQL需要撤销这些临时表。因此,子查询的速度会受到一定的影响。如果查询的数据量比较大,这种影响就会随之增大。在MySQL 中可以使用连接查询来替代子査询。连接査询不需要建立临时表,其速度比子查询要快。