【线上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一起使用

使用的索引

可能的索引

索引的长度

数据访问/读取操作类型

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

额外信息

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值