线上Case分析一次慢查询优化及总结思考

Posted 在路上的德尔菲

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了线上Case分析一次慢查询优化及总结思考相关的知识,希望对你有一定的参考价值。

背景

检查到数据库中存在慢查询情况,发现问题出现这段SQL语句中,查询此的商户是否为热点商户,如果是将更新记录时间;如果不是将插入一条数据,记录此商户为近期热点商户。

select `id`, `shopId`, `updateTime` from shop_hot_cache
where `shopId` = 1045231

 

行动

首先查看数据表结构,发现shopId是有唯一索引的。

PRIMARY KEY 'id' ('id')
UNIQUE KEY 'UQ_shopid' ('shopid')

通过EXPLAIN方法查看到,此次查询是全表扫描,没有走索引,为什么为shopId有索引却没有使用索引呢?执行EXPLAIN结果type为ALL,possible_keys为UQ_shopid,key为null。

EXPLAIN SELECT 'id' ,'shopid','updateTime' FROM shop_hot_cache
WHERE 'shopid' = 1134536

数据表中shopId为varchar格式,而输入的shopId为int类型,存在隐式转换导致不走索引。

将shopId加上引号后,再执行EXPLAIN 查询执行结果,type为const,key为UQ_shopid,rows为1,说明此时使用了索引。

EXPLAIN SELECT 'id' ,'shopid','updateTime' FROM shop_hot_cache
WHERE 'shopid' = '1134536'

代码层面修改,将入参类型由int修改为String,避免类型转换。

上线后,观察long-sql数量逐步减少为0。

 

总结思考

一、隐式转换规则

  1. 如果一个或两个参数都是NULL,比较的结果是NULL,除了NULL安全的<=>相等比较运算符。对于NULL <=> NULL,结果为true,不需要转换。
  2. 如果比较操作中的两个参数都是字符串,则将它们作为字符串进行比较。
  3. 如果两个参数都是整数,则将它们作为整数进行比较。
  4. 如果不与数字进行比较,则将十六进制值视为二进制字符串
  5. 如果其中一个参数是十进制值,则比较取决于另一个参数。 如果另一个参数是十进制或整数值,则将参数与十进制值进行比较,如果另一个参数是浮点值,则将参数与浮点值进行比较
  6. 如果其中一个参数是TIMESTAMP或DATETIME列,另一个参数是常量,则在执行比较之前将常量转换为时间戳。

二、如何避免隐式转换?

  1. 使用CAST函数或CONVERT函数显式转换
  2. 保证参数类型一致
CAST(102524307 AS CHAR)
CONVERT(102524307, CHAR)

参考:https://dev.mysql.com/doc/refman/8.0/en/cast-functions.html

三、隐式转换可能会导致哪些问题?

  1. 导致精度丢失,查询到错误数据,举个🌰:字符串'170325171202362928' 和 数值的170325171202362930 比较,会转化为'170325171202362928' 和 '170325171202362930' ,而这两个值浮点值都为1.7032517120236294e17,导致相等。
  2. 索引失效导致慢查询。

四、如何优化慢查询

  1. 考虑在选择性较好的where条件字段添加索引;
  2. 避免不必要的排序,如果必要,可以考虑通过在排序字段添加索引减小排序成本。
  3. 如果有复合索引,那么必须使用到该索引中的第一个字段作为条件时才能保证系统使用该索引,否则该索引将不会被使用。
  4. 不要对 where 条件字段进行函数、算术运算或其他表达式运算,否则可能导致无法正确使用索引。    
  5. like条件首位模糊匹配会无法使用索引,例如select id from t where name like '%abc%' 。
  6. 从逻辑上降低数据扫描量,考虑sql返回的数据是否都是必要的。比如判断是否存在符合条件的记录,使用limit 1代替count。

具体可以参考我的上一篇博客《【数据库基础干货】MySQL基础及慢查询优化实践》

五、EXPLAIN查询结果含义?

table

rows

ref

key

possible_keys

key_len

type

filtered

extra

查询哪个表

预估扫描的行数

哪个字段与key一起使用

使用的索引

可能的索引

索引的长度

数据访问/读取操作类型

此查询条件所过滤数据百分比

额外信息

 

以上是关于线上Case分析一次慢查询优化及总结思考的主要内容,如果未能解决你的问题,请参考以下文章

一次MySQL线上慢查询分析及索引使用

优化器Bug?记一次慢SQL问题分析过程

故障案例 | 一次慢SQL优化分析全过程

2022年记一次慢查询优化指南,MySQL 优化学习第9天

一次慢日志撑爆磁盘导致的业务主库宕机引发的思考

实体框架第一次查询比第二次慢得多