记一次mysql查询in的思考

  1. 从一个日常的in 查询的优化说起
  2. 使用EXPLAIN
    1. MySQL语句的执行过程
    2. 使用EXPLAIN
  3. 验证
  4. 扩展
    1. 如何创建高性能的索引
      1. 索引类型
      2. 索引的优点
    2. 为什么会慢查询

从一个日常的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根据解析、处理、优化后生成的计划。==image-20190330192427534

使用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 ,是有走索引的。

image-20190330201851186

扩展

​ 最后,再简单扩展一些MYSQL相关知识。

如何创建高性能的索引

索引类型

​ 关于索引类型,有b-tree,哈希,r-tree, 需要重点关注Innodb引擎的索引类型b-tree ,

了解聚簇索引,可以全值匹配、匹配最左前缀(例如,在使用like的时候 “a%” 索引会生效,而在使用“%a”的时候就不会生效)、匹配单列前缀、匹配范围值、只访问索引的查询(覆盖索引,索引自身包含了查询相关信息,不用再通过查询主键获取信息)。

索引的优点
  • 索引大大减少了服务器需要扫描的数据量
  • 索引可以帮助服务器避免排序和临时表
  • 索引可以将随机I/O变成顺序I/O

当然索引并不是万能的 ‘银弹’,需要考虑其选择的依据( 表的大小 、数据量) ,使用的方式(怎么使用联合索引等)以及带来的问题(频繁写表的同时也会带来索引重建、修改的损耗,索引本身的存储空间占用)

为什么会慢查询

正常情况下,主要有以下两类

  • 是否请求了不需要的数据(常见 select * ,注意这一小细节,可能会带来例如数据返回的时候会损耗时间,使用临时表等问题)
  • 扫描额外的记录(通常是未走索引,正确使用索引的姿势)

非正常情况下,即一些非可控因素 ,锁的占用,连接数耗尽等。

参考:


转载请注明来源,欢迎对文章中的引用来源进行考证,欢迎指出任何有错误或不够清晰的表达。可以在下面评论区评论,也可以邮件至 951488791@qq.com

文章标题:记一次mysql查询in的思考

字数:1.5k

本文作者:zhengyumin

发布时间:2019-03-30, 20:39:49

最后更新:2020-06-09, 17:31:55

原始链接:http://zyumin.github.io/2019/03/30/%E8%AE%B0%E4%B8%80%E6%AC%A1mysql%E6%9F%A5%E8%AF%A2in%E7%9A%84%E6%80%9D%E8%80%83/

版权声明: "署名-非商用-相同方式共享 4.0" 转载请保留原文链接及作者。