结论
mysql的in
关键字不一定走索引。
个人猜测跟传入的元素个数和索引字段离散程度有关。
验证过程
-- mysql版本
select version(); -- 5.7.28-log
-- 增加索引,该表有1849条记录,38个biz_type
ALTER TABLE `gdata_log_registry` ADD KEY `idx_biz_type` (`biz_type`);
-- 查询执行计划,已脱敏,in里有11个元素
explain SELECT * FROM `gdata_log_registry` WHERE `biz_type`
IN('A_EXPORT','B_EXPORT','EXCEPTION','CN','L_FUL','FILL','OUT','PC','TI','TIMEOUT','WM')
-- 查询执行计划,已脱敏,in里有9个元素
explain SELECT * FROM `gdata_log_registry` WHERE `biz_type`
IN('A_EXPORT','B_EXPORT','EXCEPTION','CN','L_FUL','FILL','OUT','PC','TI')
执行计划字段解释:
- id:选择标识符
- select_type:表示查询的类型。
- partitions:匹配的分区
- table:输出结果集的表
- possible_keys:sql可能使用的索引
- type:表示表的连接类型
- key:显示MySQL实际使用的索引。如果没有选择索引,键是NULL
- key_len:索引字段的长度
- ref:列与索引的比较
- rows: 显示执行查询时扫描的行数。(估算的行数)
- filtered:按表条件过滤的行百分比
- extra:描述,当出现Using filesor或Using temproary时,表示无法用索引,需要考虑做优化。
其他
type结果值从好到坏依次是:
system > const > eq_ref > ref > fulltext > ref_or_null > index_merge > unique_subquery > index_subquery > range > index > ALL
- all:全表扫描
- index:另一种形式的全表扫描,只不过他的扫描方式是按照索引的顺序
- range:有范围的索引扫描,相对于index的全表扫描,他有范围限制,因此要优于index
- ref: 查找条件列使用了索引而且不为主键和unique。其实,意思就是虽然使用了索引,但该索引列的值并不唯一,有重复。这样即使使用索引快速查找到了第一条数据,仍然不能停止,要进行目标值附近的小范围扫描。但它的好处是它并不需要扫全表,因为索引是有序的,即便有重复值,也是在一个非常小的范围内扫描。
- const:通常情况下,如果将一个主键放置到where后面作为条件查询,mysql优化器就能把这次查询优化转化为一个常量。至于如何转化以及何时转化,这个取决于优化器
一般来说,要保证查询达到range级别,最好能达到ref,type出现index和all时,表示走的是全表扫描没有走索引,当全表数据太多时效率低下,这时需要进行sql调优。
参考:
https://www.cnblogs.com/tufujie/p/9413852.html
https://blog.csdn.net/yexiaomodemo/article/details/108713770