Skip to content

面试速答(先看这里)

**一句话结论:**在这个日志的上下文不远处就定位到这条慢SQL:

60秒标准回答:

线上有一个反欺诈相关的定时任务执行连续多次失败

于是紧急排查日志,发现在任务执行的时间段,有大量报错

在这个日志的上下文不远处就定位到这条慢SQL

**答题顺序:**结论 → 原理/机制 → 关键流程 → 场景与取舍 → 易错点

回答主线:

  • **要点1:**线上有一个反欺诈相关的定时任务执行连续多次失败:
  • **要点2:**这条SQL的主要目的是找到是否有买卖家之间存在关联关系的数据。
  • **要点3:**通过这个执行计划可以发现,type = index ,extra = Using where; Using index ,表示SQL因为不符合最左前缀匹配,而扫描了整颗索引树,故而很慢。
  • **要点4:**定位到问题之后,那解决起来就很简单了,只需要增加正确的索引或者修改SQL就行了。
  • **要点5:**可以看到,type=ref,说明用到了普通索引,你并且rows也变少了,整个SQL大大提升了查询速度,任务失败的问题得到解决。

**记忆锚点:**Using → SQL → index → type → idx_byr_slr_product → where

易错提醒:

  • 线上有一个反欺诈相关的定时任务执行连续多次失败: 于是紧急排查日志,发现在任务执行的时间段,有大量报错: 在这个日志的上下文不远处就定位到这条慢SQL: 这条SQL的主要目的是找到是否有买卖家之间存在关联关系的数据。
  • 于是修改表结构,增加新的索引: 经过修改后,再执行以下执行计划: select_type fraud_risk_case partitions possible_keys idx_byr_slr_product,idx_subject_type_product_user idx_subject_type_product_user const,const fi…

追问准备:

  • 围绕「Using」:底层原理是什么?使用时有哪些边界和常见坑?
  • 围绕「SQL」:底层原理是什么?使用时有哪些边界和常见坑?
  • 围绕「index」:底层原理是什么?使用时有哪些边界和常见坑?
  • 如果线上出现异常,你会如何定位、验证并规避?

问题发现 ​

线上有一个反欺诈相关的定时任务执行连续多次失败:

image.png

于是紧急排查日志,发现在任务执行的时间段,有大量报错:

plain
Cause: ERR-CODE: [TDDL-4202][ERR_SQL_QUERY_TIMEOUT] Slow query leads to a timeout exception, please contact DBA to check slow sql. SocketTimout:12000 ms,

在这个日志的上下文不远处就定位到这条慢SQL:

plsql
select  distinct buyer_id as buyerId, seller_id as sellerId  from fraud_risk_case  WHERE subject_id_enum = 'BUYER_SELLER_BOTH' and (buyer_id = ? or seller_id = ?  ) and product_type_enum = ?   order by id desc limit 100

这条SQL的主要目的是找到是否有买卖家之间存在关联关系的数据。

通过执行explain,我们看了一下执行计划:

id1
select_typeSIMPLE
tablefraud_risk_case
partitionsNULL
typeindex
possible_keysidx_byr_slr_product
keyidx_byr_slr_product
key_len1546
refNULL
rows4133627
filtered0.19
ExtraUsing where; Using index

通过这个执行计划可以发现,type = index ,extra = Using where; Using index ,表示SQL因为不符合最左前缀匹配,而扫描了整颗索引树,故而很慢。

于是查看这张表的建表语句,确实存在subject_id_enum和product_type_enum字段的联合索引,但是这个字段并不是前导列:

plsql
idx_subject_product(subject_id,subject_id_enum,product_type)

问题解决 ​

定位到问题之后,那解决起来就很简单了,只需要增加正确的索引或者修改SQL就行了。于是修改表结构,增加新的索引:

plsql
ALTER TABLE `fraud_risk_case`
	ADD KEY `idx_subject_type_product_user` (`subject_id_enum`,`product_type_enum`,`buyer_id`,`seller_id`);

经过修改后,再执行以下执行计划:

id1
select_typeSIMPLE
tablefraud_risk_case
partitionsNULL
typeref
possible_keysidx_byr_slr_product,idx_subject_type_product_user
keyidx_subject_type_product_user
key_len516
refconst,const
rows1
filtered19.00
ExtraUsing where; Using index; Using temporary; Using filesort

可以看到,type=ref,说明用到了普通索引,你并且rows也变少了,整个SQL大大提升了查询速度,任务失败的问题得到解决。

image.png

参考:

📄 ✅SQL执行计划分析的时候,要关注哪些信息?

打开文档:✅SQL执行计划分析的时候,要关注哪些信息?