从一个日常的in 查询的优化说起
业务场景需要 select * from table where id in( )
, 然后就会抛出一个问题,使用in 会不会走索引?
对于这个问题,因为之前在网上看过说不会,说会的,充斥着各种说法,然后自己对这块也是很久之前看过。参考了一些资料。写下自己的思考。
其实关于这个问题,我们需要缩小范围,首先是确定版本,版本意识很重要,这里我们讨论建立在5.5.39-log 这个版本上。(使用 select version()
; 命令可以查看当前版本)
使用EXPLAIN
当您在SELECT
带有关键字的语句 之前时EXPLAIN
,MySQL会显示优化程序中有关语句执行计划的信息。也就是说,MySQL解释了它将如何处理语句,包括有关如何连接表以及以何种顺序连接的信息。
MySQL语句的执行过程
首先我们要了解何为执行计划,这又得从一条SQL语句的执行过程说起(这个在高性能mysql的6.4节中有介绍)
整个查询流程大致如下
- 客户端向 MySQL 服务器发送一条查询请求(半双工,即客户端和服务器不能互相通信)
- 服务器首先检查查询缓存,如果命中缓存,则立刻返回存储在缓存中的结果,否则进入下一阶段。
- 服务器进行 SQL 解析(通过语法规则来验证和解析,生成解析树)、预处理(检查要查询的数据表和数据列是否存在)、再由优化器生成最优的执行计划。
- MySQL 根据执行计划,调用存储引擎的 API 来执行查询。
- 将结果返回给客户端,同时缓存查询结果。
==简单来说,执行计划就是MySQL根据解析、处理、优化后生成的计划。==
使用EXPLAIN
具体用法如下explain select * from table where id in( )
,返回输出结果如下(官方网站的链接如下https://dev.mysql.com/doc/refman/5.5/en/explain-output.html)
Column | Meaning |
---|---|
id |
The SELECT identifier |
select_type |
The SELECT type |
table |
The table for the output row |
partitions |
The matching partitions |
type |
The join type |
possible_keys |
The possible indexes to choose |
key |
The index actually chosen |
key_len |
The length of the chosen key |
ref |
The columns compared to the index |
rows |
Estimate of rows to be examined |
filtered |
Percentage of rows filtered by table condition |
Extra |
Additional information |
这里我们注意点是select_type 、type、possible_keys、key、rows、Extra(更多细节可以查看官方文档)
select_type
: 表示了查询的类型,常见的是SIMPLE,这个是在有子查询、联合查询需要注意的。
type
:这个字段比较重要, 它提供了判断查询是否高效的重要依据依据. 通过 type
字段, 我们判断此次查询是 全表扫描
还是 索引扫描
等.
根据性能:
ALL < index < range ~ index_merge < ref < eq_ref < const < system
除了ALL,其他都是走索引
possible_keys
:表示可以选择的索引
key
:表示执行时候真正使用的索引
ref
: 该ref
列显示将哪些列或常量与列中指定的索引进行比较(例如联合索引的时候,命中了几个),以 key
从表中选择行。
rows
:扫描的行数
Extra
:也是比较重要的一个字段,常见的类型如下
Using filesort,表示MySQL必须执行额外的传递以找出如何按排序顺序检索行。
Using index,仅需要从索引树中获取,例如通过主键查询(聚合索引类型,所以主键上带有key的所有信息),或者是命中索引,且仅取索引上的相关字段。
Using where,表示限制哪些行与下一个表匹配或发送到客户端。 除非特意打算从表中获取或检查所有行,否则如果Extra值是Using where并且表连接类型为ALL或index,则可以是查询有问题了。
验证
有了上述相关知识,我们就可以用explain select * from table where id in( )
来获取相关信息分析,可以发现 type为range ,Extra 为Using where ,是有走索引的。
扩展
最后,再简单扩展一些MYSQL相关知识。
如何创建高性能的索引
索引类型
关于索引类型,有b-tree,哈希,r-tree, 需要重点关注Innodb引擎的索引类型b-tree ,
了解聚簇索引,可以全值匹配、匹配最左前缀(例如,在使用like的时候 “a%” 索引会生效,而在使用“%a”的时候就不会生效)、匹配单列前缀、匹配范围值、只访问索引的查询(覆盖索引,索引自身包含了查询相关信息,不用再通过查询主键获取信息)。
索引的优点
- 索引大大减少了服务器需要扫描的数据量
- 索引可以帮助服务器避免排序和临时表
- 索引可以将随机I/O变成顺序I/O
当然索引并不是万能的 ‘银弹’,需要考虑其选择的依据( 表的大小 、数据量) ,使用的方式(怎么使用联合索引等)以及带来的问题(频繁写表的同时也会带来索引重建、修改的损耗,索引本身的存储空间占用)
为什么会慢查询
正常情况下,主要有以下两类
- 是否请求了不需要的数据(常见 select * ,注意这一小细节,可能会带来例如数据返回的时候会损耗时间,使用临时表等问题)
- 扫描额外的记录(通常是未走索引,正确使用索引的姿势)
非正常情况下,即一些非可控因素 ,锁的占用,连接数耗尽等。
参考:
转载请注明来源,欢迎对文章中的引用来源进行考证,欢迎指出任何有错误或不够清晰的表达。可以在下面评论区评论,也可以邮件至 951488791@qq.com