mysql

MySQL索引优化策略

2019-01-31  本文已影响7人  南风nanfeng

1. 使用EXPLAIN

使用EXPLAIN关键字可以帮助我们分析select语句,让我们知道查询效率低下的原因,从而改进我们查询,让查询优化器能够更好的工作。

基本思路

字段解释

[图片上传失败...(image-9bbeb8-1511505009818)]

列名 说明
id 执行编号,标识select所属的行。如果在语句中没子查询或关联查询,只有唯一的select,每行都将显示1。否则,内层的select语句一般会顺序编号,对应于其在原始语句中的位置
select_type 显示本行是简单或复杂select。如果查询有任何复杂的子查询,则最外层标记为PRIMARY(DERIVED、UNION、UNION RESUlT)
table 访问引用哪个表(引用某个查询,如“derived3”)
type 数据访问/读取操作类型(ALL、index、range、ref、eq_ref、const/system、NULL)javascript:void(null)
possible_keys 揭示哪一些索引可能有利于高效的查找
key 显示mysql决定采用哪个索引来优化查询
key_len 显示mysql在索引里使用的字节数
ref 显示了之前的表在key列记录的索引中查找值所用的列或常量
rows 为了找到所需的行而需要读取的行数,估算值,不精确。通过把所有rows列值相乘,可粗略估算整个查询会检查的行数
Extra 额外信息,如using index、filesort等

select_type列:

select_type 说明
SUBQUERY 在select列表中的子查询,如SELECT *,(SELECT id FROM product_info) AS id FROM product_info
DERIVED 在from子语句中子查询,如SELECT * FROM product_info p1 ,(SELECT * FROM product_info) p2.Mysql会递归执行,并把结果放到临时表中
UNION 在UNION中第二个和随后的SELECT被标记为UNION
UNION RESULT 用来从UNION的匿名临时表检索结果的SELECT被标记为UNION RESULT
DEPENDENT SUBQUERY 子查询中的第一个SELECT,取决于外面的查询。(需要优化)

type列(依次从最差到最优):

type 说明
All 最坏的情况,从头到尾全表扫描
index 和全表扫描一样。只是扫描表的时候按照索引次序进行而不是行。主要优点就是避免了排序, 但是开销仍然非常大。如在Extra列看到Using index,说明正在使用覆盖索引,只扫描索引的数据,它比按索引次序全表扫描的开销要小很多
range 范围扫描,一个有限制的索引扫描。key 列显示使用了哪个索引。当使用=、 <>、>、>=、<、<=、IS NULL、<=>、BETWEEN 或者 IN 操作符,用常量比较关键字列时,可以使用 range
ref 一种索引访问,它返回所有匹配某个单个值的行。此类索引访问只有当使用非唯一性索引或唯一性索引非唯一性前缀时才会发生
eq_ref 最多只返回一条符合条件的记录。使用唯一性索引或主键查找时会发生 (高效)
const/system 当主键放入where子句时,mysql把这个查询转为一个常量(高效)
Null 意味说mysql能在优化阶段分解查询语句,在执行阶段甚至用不到访问表或索引(高效)

Extra列常见情况(需要优化):

Extra 说明
Using temporary 表示 MySQL 在对查询结果排序时使用临时表。常见于排序 order by 和分组查询 group by
Using filesort 表示 MySQL 会对结果使用一个外部索引排序,而不是从表里按索引次序读到相关内容。可能在内存或者磁盘上进行排序。MySQL 中无法利用索引完成的排序操作称为“文件排序”

2. 建索引

索引并不一定就是给主键或是唯一的字段。如果在你的表中,有某个字段你总要会经常用来做搜索,那么,请为其建立索引吧。

基本原则

优化策略A:字段选择性

优化策略B:组合索引字段顺序

由于 mysql 索引是基于 B-Tree 的,所以组合索引有“字段顺序”概念。

所以,查询条件中有 ac.city_id IN (0, 8005),而组合索引是 (ads_id,city_id),则该查询无法使用到这个组合索引。

组合索引查询的各种场景

兹有 Index (A,B,C) ——组合索引多字段是有序的,并且是个完整的BTree索引。
下面条件可以用上该组合索引查询:

A>5
A=5 AND B>6
A=5 AND B=6 AND C=7
A=5 AND B IN (2,3) AND C>5

下面条件将不能用上组合索引查询:

B>5 ——查询条件不包含组合索引首列字段
B=6 AND C=7 ——查询条件不包含组合索引首列字段

下面条件将能用上部分组合索引查询:

A>5 AND B=2 ——当范围查询使用第一列,查询条件仅仅能使用第一列
A=5 AND B>6 AND C=2 ——范围查询使用第二列,查询条件仅仅能使用前二列

组合索引排序的各种场景

兹有组合索引 Index(A,B)。
下面条件可以用上组合索引排序:

ORDER BY A——首列排序
A=5 ORDER BY B——第一列过滤后第二列排序
ORDER BY A DESC, B DESC——注意,此时两列以相同顺序排序
A>5 ORDER BY A——数据检索和排序都在第一列

下面条件不能用上组合索引排序:

ORDER BY B ——排序在索引的第二列
A>5 ORDER BY B ——范围查询在第一列,排序在第二列
A IN(1,2) ORDER BY B ——理由同上
ORDER BY A ASC, B DESC ——注意,此时两列以不同顺序排序

索引合并

顺着组合索引怎么建继续往下延伸,请各位注意“索引合并”概念:

索引合并的简单说明:

  1. SELECT * FROM TB WHERE A=5 AND B=6
    • 能分别使用索引(A) 和 (B) 或 索引合并;
    • 创建组合索引(A,B) 更好;
  2. SELECT * FROM TB WHERE A=5 OR B=6
    • 能分别使用索引(A) 和 (B) 或 索引合并;
    • 组合索引(A,B)不能用于此查询,分别创建索引(A) 和 (B)会更好;

3. 表设计

3.1 尽可能的使用NOT NULL

3.2 使用紧凑的数据类型

3.3 永远为每张表设置一个ID

3.4 选择合适的存储引擎

在MySQL中有两个存储引擎MyISAM和InnoDB,每个引擎都有利有弊。

4. 查询语句

4.1 避免 SELECT *

从数据库里读出越多的数据,那么查询就会变得越慢。并且,如果你的数据库服务器和WEB服务器是两台独立的服务器的话,这还会增加网络传输的负载。

4.2 当只要一行数据时使用LIMIT 1

当你查询表的有些时候,你已经知道结果只会有一条结果,但因为你可能需要去fetch游标,或是你也许会去检查返回的记录数。
在这种情况下,加上LIMIT 1可以增加性能。这样一样,MySQL数据库引擎会在找到一条数据后停止搜索,而不是继续往后查少下一条符合记录的数据。

4.3 为查询缓存优化你的查询

大多数的MySQL服务器都开启了查询缓存。这是提高性最有效的方法之一,而且这是被MySQL的数据库引擎处理的。当有很多相同的查询被执行了多次的时候,这些查询结果会被放到一个缓存中,这样,后续的相同的查询就不用操作表而直接访问缓存结果了。
这里最主要的问题是,对于程序员来说,这个事情是很容易被忽略的。因为,我们某些查询语句会让MySQL不使用缓存。请看下面的示例:
[图片上传失败...(image-238fbd-1511505009818)]

上面两条SQL语句的差别就是CURDATE(),MySQL的查询缓存对这个函数不起作用。所以,像NOW()和RAND()或是其它的诸如此类的SQL函数都不会开启查询缓存,因为这些函数的返回是会不定的易变的。所以,你所需要的就是用一个变量来代替MySQL的函数,从而开启缓存。

4.4 在Join表的时候使用相同类型的列,并将其索引

4.5 不要ORDER BY RAND()

如果你真的想把返回的数据行打乱了,你有N种方法可以达到这个目的。这样使用只让你的数据库的性能呈指数级的下降。这里的问题是:MySQL会不得不去执行RAND()函数(很耗CPU时间),而且这是为了每一行记录去记行,然后再对其排序。就算是你用了Limit 1也无济于事(因为要排序)

4.6 Prepared Statements

4.7 拆分大的DELETE或INSERT语句

5. 其他

5.1 固定长度的表会更快

5.2 从PROCEDURE ANALYSE()取得建议

5.3 垂直分割

上一篇 下一篇

猜你喜欢

热点阅读