今天是清明假期的第三天,收到同事的求助,DB的CPU被打爆了!
查看监控,CPU已经被打爆100%
登录mysql,DB无锁阻塞,元凶是一个异常sql,存在39个并发执行。
SQL的明细如下:
select TEMPSALE.USER_ID_BUY, TEMPSALE.ORDER_AMOUNT, TEMPSALE.LAST_UPDATED_DATEfrom T_EAC_BU_SG_CO_INFO TSIrightjoin (select TOI.SALE_PRO_ID, TOI.USER_ID_BUY, TOI.ORDER_AMOUNT, TOI.LAST_UPDATED_DATE from T_EAC_BU_ORDER_INFO TOI left join T_EAC_BU_SALE_GOOD_INFO TEC on TOI.SALE_PRO_ID = TEC.SALE_PRO_ID) TEMPSALE on TSI.SALE_PRO_ID = TEMPSALE.SALE_PRO_IDwhere TSI.CAR_ORIGIN_CODE= '000000008671c3180186829f41ad336f' ;
首先看看该sql的执行计划吧
相关的表结构如下:
分析:
先来看看正常情况下这条sql单次执行耗时为多少
索引有缺失吗?
相关表的索引创建无大碍,关联字段与where谓词字段都已经创建好了索引。
针对这条异常sql,我们还有优化的空间吗??
解读执行计划,扫描 表别名为 TOI的表,全表扫描估算数据量为514049, Extra 列为 NULL 没有任何的谓词过滤无效数据。扫描后的结果与 表别名为 TEC 的表 Using index (SALE_PRO_ID字段)进行关联。再与 表别名为 TSI 的表 Using where 使用谓词过滤后关联。
执行耗时绝大部分耗时都在第一步与第二步,即 from T_EAC_BU_ORDER_INFO TOI left join T_EAC_BU_SALE_GOOD_INFO TEC on TOI.SALE_PRO_ID = TEC.SALE_PRO_ID ,在不影响语义的前提下,
我们改写sql把能过滤大部分数据的谓词表提前作为驱动表执行,这样就能最大程度提高执行效率,缩短执行时间了。即,我们将原本 T_EAC_BU_ORDER_INFO 与 T_EAC_BU_SALE_GOOD_INFO 无谓词的关联,改写为 T_EAC_BU_ORDER_INFO 与 T_EAC_BU_SG_CO_INFO 带谓词关联。
改写后的sql
未优化前sql与优化后sql执行时间对比
未优化前sql与优化后sql执行计划对比
至此,原本执行耗时由9秒+的问题sql,优化至0.00秒,性能提升杠杠的。
总结:
1、多表关联,表谓词能提前的提前过滤无效数据
2、多表关联,小表驱动大表
3、大部分sql优化为最佳索引缺失,部分sql优化需要改写sql