作者:微信小助手
发布时间:2022-06-02T18:38:11
日常开发中,我们经常会遇到数据库慢查询 。那么导致数据慢查询都有哪些常见的原因呢?今天田螺哥就跟大家聊聊导致MySQL慢查询的12个常见原因,以及对应的解决方法。 很多时候,我们的慢查询,都是因为没有加索引 。如果没有加索引的话,会导致全表扫描的。因此,应考虑在 反例: 正例: 基于 Spring Boot + MyBatis Plus + Vue & Element 实现的后台管理系统 + 用户小程序,支持 RBAC 动态权限、多租户、数据权限、工作流、三方登录、支付、短信、商城等功能。 项目地址:https://github.com/YunaiV/ruoyi-vue-pro 有时候我们明明加了索引了,但是索引却不生效。在哪些场景,索引会不生效呢?主要有以下十大经典场景: 我们创建一个用户user表 如果给数字加上 为什么第一条语句未加单引号就不走索引 了呢?这是因为不加单引号时,是字符串跟数字的比较,它们类型不匹配,MySQL会做隐式的类型转换 ,把它们转换为浮点数再做比较。隐式的类型转换,索引会失效。 我们还是用这个表结构: 其中 对于 注意 :如果 并不是用了 like查询以 把 既然 MySQl建立联合索引时,会遵循最左前缀匹配的原则,即最左优先。如果你建立一个 假设有以下表结构: 有一个联合索引 因为查询条件列 在联合索引中,查询条件满足最左匹配原则 时,索引才正常生效。 表结构: 虽然 一般这种情况怎么优化呢?可以把内置函数的逻辑转移到右边 ,如下: 表结构: 虽然 所以不可以对索引列进行运算,可以在代码处理好,再传参进去 。 表结构: 虽然1. SQL没加索引
where
的条件列,建立索引 ,尽量避免全表扫描。select * from user_info where name ='捡田螺的小男孩' ;
//添加索引
alter table user_info add index idx_name (name);
2. SQL 索引不生效
2.1 隐式的类型转换,索引失效
CREATE TABLE user (
id int(11) NOT NULL AUTO_INCREMENT,
userId varchar(32) NOT NULL,
age varchar(16) NOT NULL,
name varchar(255) NOT NULL,
PRIMARY KEY (id),
KEY idx_userid (userId) USING BTREE
) ENGINE=InnoDB DEFAULT CHARSET=utf8;userId
字段为字串类型 ,是B+树的普通索引,如果查询条件传了一个数字 过去,会导致索引失效。如下:
''
,也就是说,传的是一个字符串呢,当然是走索引 ,如下图:
2.2 查询条件包含or,可能导致索引失效
CREATE TABLE user (
id int(11) NOT NULL AUTO_INCREMENT,
userId varchar(32) NOT NULL,
age varchar(16) NOT NULL,
name varchar(255) NOT NULL,
PRIMARY KEY (id),
KEY idx_userid (userId) USING BTREE
) ENGINE=InnoDB DEFAULT CHARSET=utf8;userId
加了索引,但是age
没有加索引的。我们使用了or
,以下SQL是不走索引的,如下:
or
+没有索引的age
这种情况,假设它走了userId
的索引,但是走到age
查询条件时,它还得全表扫描,也就是需要三步过程:全表扫描+索引扫描+合并 。如果它一开始就走全表扫描 ,直接一遍扫描就完事。Mysql优化器出于效率与成本考虑,遇到or
条件,让索引失效,看起来也合情合理嘛。or
条件的列都加了索引,索引可能会走也可能不走 ,大家可以自己试一试哈。但是平时大家使用的时候,还是要注意一下这个or
,学会用explain
分析。遇到不走索引的时候,考虑拆开两条SQL。2.3. like通配符可能导致索引失效。
like
通配符,索引一定会失效,而是like查询是以%
开头,才会导致索引失效。%
开头,索引失效explain select * from user where userId like '%123';
%
放后面,发现索引还是正常走的,如下:explain select * from user where userId like '123%';
like
查询以%
开头,会导致索引失效。我们如何优化呢?
%
放后面
2.4 查询条件不满足联合索引的最左匹配原则
(a,b,c)
的联合索引,相当于建立了(a)、(a,b)、(a,b,c)
三个索引。CREATE TABLE user (
id int(11) NOT NULL AUTO_INCREMENT,
user_id varchar(32) NOT NULL,
age varchar(16) NOT NULL,
name varchar(255) NOT NULL,
PRIMARY KEY (id),
KEY idx_userid_name (user_id,name) USING BTREE
) ENGINE=InnoDB DEFAULT CHARSET=utf8;idx_userid_name
,我们执行这个SQL,查询条件是name
,索引是无效:explain select * from user where name ='捡田螺的小男孩';
name
不是联合索引idx_userid_name
中的第一个列,索引不生效
2.5 在索引列上使用mysql的内置函数
CREATE TABLE `user` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`userId` varchar(32) NOT NULL,
`login_time` datetime NOT NULL,
PRIMARY KEY (`id`),
KEY `idx_userId` (`userId`) USING BTREE,
KEY `idx_login_time` (`login_Time`) USING BTREE
) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8;login_time
加了索引,但是因为使用了mysql
的内置函数Date_ADD()
,索引直接GG,如图:
explain select * from user where login_time = DATE_ADD('2022-05-22 00:00:00',INTERVAL -1 DAY);
2.6 对索引进行列运算(如,+、-、*、/),索引不生效
CREATE TABLE `user` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`userId` varchar(32) NOT NULL,
`age` int(11) DEFAULT NULL,
PRIMARY KEY (`id`),
KEY `idx_age` (`age`) USING BTREE
) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8;age
加了索引,但是因为它进行运算,索引直接迷路了。。。如图:
2.7 索引字段上使用(!= 或者 < >),索引可能失效
CREATE TABLE `user` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`userId` int(11) NOT NULL,
`age` int(11) DEFAULT NULL,
`name` varchar(255) NOT NULL,
PRIMARY KEY (`id`),
KEY `idx_age` (`age`) USING BTREE
) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8;age
加了索引,但是使用了!=
或者