SQL调优之字符集-Range checked for each record (index map: 0x2)

一、背景

项目中有些业务涉及到多个表的关联查询,每个表都有大量数据,因此查询起来很慢,需要对其进行优化。通过explain进行分析过程中发现,有个关联查询增加索引的字段居然没有起作用,并且有提示信息:Range checked for each record (index map: 0x2)。通过查询相关资料,发现是两个数据表字符集不匹配的问题。复盘如下:

二、复盘

测试环境准备:

对联合查询语句进行分析:

explain
select * from 
t_t_user tt
LEFT JOIN t_t_user_info tti ON tt.`code` = tti.`code`
order by tt.id asc limit 100

分析结果:

关键语句:Range checked for each record (index map: 0x2)

解决方案:

在navicat里面选择数据表,然后点击“设计表”,修改表和字段的字符集

也可以使用语句(不过这种方式,如果数据量很大的话,需要执行比较久,建议使用工具):

ALTER TABLE `t_t_user` MODIFY COLUMN `code` varchar(40) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT 编码;

修改后:

但是,测试结果如图:

Using temporary与Using filesort 这个什么意思? Using temporary表示排序没有走索引。 Using filesort表示没有使用索引的排序。 Why?原因很简单嘛,数据量不够。所以我们需要使用循环语句进行大量造数据。

-- t_t_user_info新增1000条数据
DELIMITER //
DROP PROCEDURE if EXISTS ‘test1’;    
CREATE procedure test1() 
BEGIN
DECLARE i INT;  
SET i = 5;  
WHILE i<1000 DO 
INSERT INTO `t_t_user_info` VALUES (i, i, 001, ll, ll, 1, 2021-12-16 11:50:56, 2021-12-15 11:51:03);
SET i = i+1;   
END WHILE;  
SELECT * FROM t_t_user_info; 
END
//
CALL test1();    
DELIMITER ;
-- t_t_user新增1000条数据
DELIMITER //
DROP PROCEDURE if EXISTS ‘test’;    
CREATE procedure test() 
BEGIN
DECLARE i INT;  
SET i = 5;  
WHILE i<1000 DO 
INSERT INTO `t_t_user` VALUES (i, i, 001, ll, ll, 1, 2021-12-16 11:50:56, 2021-12-15 11:51:03);
SET i = i+1;   
END WHILE;  
SELECT * FROM t_t_user; 
END
//
CALL test();    
DELIMITER ;

再次执行explain语句,效果出现了:

我们反向重新将t_t_user表修改为utf8_bin,同样的问题再次出现,复盘完毕。

三、参考文献

1、SQL调优—Range checked for each record (index map: 0x1) https://blog..net/hzr0523/article/details/118928185 2、Using temporary与Using filesort https://blog..net/sz85850597/article/details/91907988 3、MySQL循环语句 http://blog.itpub.net/69955379/viewspace-2753943/

经验分享 程序员 微信小程序 职场和发展