MySQL 的 in 查询到底走不走索引?
首先说一下,我的测试环境:
MySQL 版本:SELECT VERSION();
创建测试表zxl_test
CREATE TABLE `zxl_test` (
`id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '主键ID',
`name` varchar(255) NOT NULL,
`title` varchar(255) DEFAULT NULL,
`page` bigint(20) DEFAULT NULL,
`status` tinyint(3) unsigned NOT NULL COMMENT '状态:0 正常,1 冻结,2 删除',
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=0 DEFAULT CHARSET=utf8mb4;
循环插入 100 万条测试数据
DELIMITER ;;
CREATE PROCEDURE test_insert()
BEGIN
declare i int;
set i = 1 ;
WHILE (i < 1000000) DO
INSERT INTO zxl_test(`name`,title,`page`,`status`)
VALUES(CONCAT('zxl_', i),
CONCAT('zxl_title_', i),
i, (SELECT FLOOR(RAND() * 2)));
set i = i + 1;
END WHILE;
commit;
END;;
CALL test_insert();
name列in查询:
status列in查询:
可以看到表中的 name 值已经非常的散了,查询时间0.393秒左右,表中的 status in 的情况,耗时 17 秒左右
再看一下主键ID in的查询:
查询时间耗时 0.009秒左右
为了比较,给name列加上索引,in 查询耗时 0.02 秒左右
CREATE INDEX index_zxl_test_name ON zxl_test(`name`(255));
EXPLAIN 分析发现它们的 type 都是 range,表示使用索引范围查询, 通过索引字段范围获取表中部分数据记录. 这个类型通常出现在 =,<>,>,>=,<,<=,IS NULL,<=>,BETWEEN,IN() 操作中。而且 possible_keys 的值也表明了分别使用主键索引和 index_xttblog_name 索引。并且在 in 索引的情况下,rows 的值,大家都可以看到是 4。以上就可以证明了,在 MySQL 5.7 版本中,in 在有索引的情况下,会走索引进行查询。
给status列加上索引,in查询耗时17.483秒
CREATE INDEX index_zxl_test_status ON zxl_test(`status`);
可以看到有索引和没有索引查询的时间差不多
猜想:如果把status字段改为char类型呢?
alter table zxl_test MODIFY COLUMN status CHAR(2) NOT NULL COMMENT '状态:0 正常,1 冻结,2 删除'
发现并没有提升,接着改为varchar类型的
同样的,查询效率还是差不多
试试无索引,分页查询, 发现用时0.059s
试一下有索引,分页查询, 发现用时0.040s,稍微提升了一点
结论:MySQL 的 in 查询是会走索引的
注意:如果使用in查询,如果结果集中的数据非常多,尽量分页查询处理,不然查询的效率也会低