12个MySQL慢查询的原因分析

当内存数据页跟磁盘数据页内容不一致的时候,我们称这个内存页为“脏页”。内存数据写入到磁盘后,内存和磁盘上的数据页的内容就一致了,称为“干净页”。一般有更新SQL才可能会导致脏页,我们回忆一下一条更新语句是如何执行的。...
摘要由CSDN通过智能技术生成

1. SQL 没加索引

很多时候,我们的慢查询,都是因为没有加索引。如果没有加索引的话,会导致全表扫描的。因此,应考虑在 where 的条件列,建立索引,尽量避免全表扫描。

反例:

select * from user_info where name =‘捡田螺的小男孩公众号’ ;

正例:

//添加索引 alter table user_info add index idx_name (name);

========================================================================

2. SQL 索引不生效

有时候我们明明加了索引了,但是索引却不生效。在哪些场景,索引会不生效呢?主要有以下十大经典场景:

2.1 隐式的类型转换,索引失效

我们创建一个用户 user 表

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 + 树的普通索引,如果查询条件传了一个数字过去,会导致索引失效。如下:

如果给数字加上’', 也就是说,传的是一个字符串呢,当然是走索引,如下图:

为什么第一条语句未加单引号就不走索引了呢?这是因为不加单引号时,是字符串跟数字的比较,它们类型不匹配,MySQL 会做隐式的类型转换,把它们转换为浮点数再做比较。隐式的类型转换,索引会失效。

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 查询是以 % 开头,才会导致索引失效。

like 查询以 % 开头,索引失效

explain select * from user where userId like ‘%123’;

把 % 放后面,发现索引还是正常走的,如下:

explain select * from user where userId like ‘123%’;

既然 like 查询以 % 开头,会导致索引失效。我们如何优化呢?

  • 使用覆盖索引
  • 把 % 放后面

2.4 查询条件不满足联合索引的最左匹配原则

MySQl 建立联合索引时,会遵循最左前缀匹配的原则,即最左优先。如果你建立一个(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 TABLEuser(idint(11) NOT NULL AUTO_INCREMENT,userIdvarchar(32) NOT NULL,login_timedatetime NOT NULL, PRIMARY KEY (id), KEYidx_userId(userId) USING BTREE, KEYidx_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 TABLEuse

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
MySQL 慢查询日志可以记录执行时间超过指定阈值的 SQL 查询语句,用于帮助 DBA 或开发者监控和优化 SQL 查询性能。 以下是 MySQL 慢查询日志分析的一般步骤: 1. 开启 MySQL 慢查询日志。在 MySQL 配置文件中设置 `slow_query_log` 参数为 `ON`,并指定 `slow_query_log_file` 参数为日志文件路径。 2. 查看慢查询日志。可以使用 `mysqldumpslow` 工具或者其他第三方工具来查看慢查询日志,例如: ``` mysqldumpslow -s t /path/to/slow_query_log_file ``` 上面的命令会按照时间排序并显示执行时间最长的 SQL 查询语句。 3. 分析慢查询语句。对于执行时间较长的 SQL 查询语句,可以进行如下分析: - 检查 SQL 查询语句是否存在索引。可以使用 `EXPLAIN` 命令或者其他第三方工具来查看 SQL 查询语句的执行计划,判断是否存在全表扫描或者索引失效等问题。 - 检查 SQL 查询语句的优化方式。可以考虑对 SQL 查询语句进行重构,使用更优的语法或者查询方式,例如使用 JOIN、子查询等方式来替代多次查询。 - 检查 MySQL 数据库的配置参数。可以根据查询语句的特点来调整 MySQL 数据库的配置参数,例如 `innodb_buffer_pool_size`、`max_connections`、`query_cache_size` 等参数。 4. 优化慢查询语句。根据分析结果,对 SQL 查询语句、MySQL 数据库配置参数等进行优化,提高查询性能。 总之,MySQL 慢查询日志分析需要结合实际情况和经验进行,需要不断地监控和优化,以提高 MySQL 数据库的性能和稳定性。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值