数据库字段明明有加索引,却查询效率这么低,教你避免采坑的五大方法

前提:数据准备

drop table if exists t1; /* 如果表t1存在则删除表t1 */

CREATE TABLE `t1` ( /* 创建表t1 */
`id` int(11) NOT NULL AUTO_INCREMENT,
`a` varchar(20) DEFAULT NULL,
`b` int(20) DEFAULT NULL,
`c` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP,
PRIMARY KEY (`id`),
KEY `idx_a` (`a`) USING BTREE,
KEY `idx_b` (`b`) USING BTREE,
KEY `idx_c` (`c`) USING BTREE
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;

drop procedure if exists insert_t1; /* 如果存在存储过程insert_t1,则删除 */
delimiter ;;
create procedure insert_t1() /* 创建存储过程insert_t1 */
begin
declare i int; /* 声明变量i */
set i=1; /* 设置i的初始值为1 */
while(i<=10000)do /* 对满足i<=10000的值进行while循环 */
insert into t1(a,b) values(i,i); /* 写入表t1中a、b两个字段,值都为i当前的值 */
set i=i+1; /* 将i加1 */
end while;
end;;
delimiter ;
call insert_t1(); /* 运行存储过程insert_t1 */

update t1 set c = '2019-05-22 00:00:00'; /* 更新表t1的c字段,值都为'2019-05-22 00:00:00' */
update t1 set c = '2019-05-21 00:00:00' where id=10000; /* 将id为10000的行的c字段改为与其它行都不一样的数据,以便后面实验使用 */

1.要查询测试表 t1 单独某一天的所有数据

explain select * from t1 where date(c) ='2019-05-21';

查看图中的执行计划,type 为 ALL,key 字段结果为 NULL,因此知道该 SQL 是没走索引的全表扫描

原因:对条件字段做函数操作走不了索引

2.隐式转换

概念:当操作符与不同类型的操作对象一起使用时,就会发生类型转换以使操作兼容。某些转换是隐式的

explain select * from t1 where a=1000;

未走索引原因:

a 字段类型是 varchar(20),而语句中 a 字段条件值没加单引号,导致 MySQL 内部会先把a转换成int型,再去做判断,相当于实际执行的 SQL 语句如下:

select * from t1 where cast(a as signed int) =1000;

因此又回到上面说的:对索引字段做函数操作时,优化器会放弃使用索引

优化后:

explain select * from t1 where a='1000';

隐式转换导致查询慢的情况在工作中遇到过几次,有时字段名对开发写SQL产生了影响,比如曾经遇到过字段名是user_num,而实际字段类型是char,但是开发在写SQL时误认为是int型,导致漏写单引号而发生隐式转换。

所以建议在写SQL时,先看字段类型,然后根据字段类型写SQL 

3.模糊查询(通配符在前面不走索引)

很多时候我们想根据某个字段的某几个关键字查询数据,比如会有如下 SQL:

 优化过的:

 缺点:结果会不准确

如果条件只知道中间的值,需要模糊查询去查,那就建议使用ElasticSearch或其它搜索服务器

4.范围查询:

explain select * from t1 where b>=1 and b <=2000;

 结果:不走索引

发现并不能走b字段的索引。

原因:优化器会根据检索比例、表大小、I/O块大小等进行评估是否使用索引。比如单次查询的数据量过大,优化器将不走索引。

优化范围查询(分批查询)

explain select * from t1 where b>=1 and b <=1000;

 实际这种范围查询而导致使用不了索引的场景经常出现,比如按照时间段抽取全量数据,每条SQL抽取一个月的;或者某张业务表历史数据的删除。遇到此类操作时,应该在执行之前对SQL做explain分析,确定能走索引,再进行操作,否则不但可能导致操作缓慢,在做更新或者删除时,甚至会导致表所有记录锁住,十分危险。

5.计算操作:

explain select * from t1 where b-1 =1000;

 原因:对索引字段做运算将使用不了索引。

计算操作的 SQL 优化

explain select * from t1 where b =1000 + 1;

 一般需要对条件字段做计算时,建议通过程序代码实现,而不是通过MySQL实现。如果在MySQL中计算的情况避免不了,那必须把计算放在等号后面

总结以上结果:
  • 应该避免隐式转换
  • like查询不能以%开头
  • 范围查询时,包含的数据比例不能太大
  • 不建议对条件字段做运算及函数操作




猜你喜欢

转载自www.cnblogs.com/php-json/p/13367939.html