生產上面有一條sql查詢很慢,需要7到8秒左右,簡化之后的sql如下所示:
SELECT mingxi.* FROM ( SELECT btjc01.id, department.`name` AS btjc01011, btjc01011 AS obj, btjc01.inibeginmonth AS beginYearMonth, lsbtsj.btje AS btjc01030, CASE WHEN btjc01.inibeginmonth ='2019-10' THEN '是' ELSE '否' END AS isadd FROM btjc01 INNER JOIN department ON department.Id = btjc01.btjc01038 INNER JOIN lsbtsj ON lsbtsj.btrid = btjc01.Id WHERE btjc01.btjc01037 = '3' AND btjc01046 ='江西省' AND btjc01047 ='九江市' AND btjc01048 ='修水縣' AND lsbtsj.btqsyf <='2019-10' AND lsbtsj.btjzyf >='2019-10' AND beginYearMonth != inibeginmonth UNION ALL SELECT btjc01.id, department.`name` AS btjc01011, btjc01011 AS obj, btjc01.beginYearMonth, btjc01.btjc01030, CASE WHEN btjc01.inibeginmonth ='2019-10' THEN '是' ELSE '否' END AS isadd FROM btjc01 INNER JOIN department ON department.Id = btjc01.btjc01038 INNER JOIN btgg03 ON btgg03.Id = btjc01.btjc01040 WHERE btjc01.btjc01037 = '3' AND btjc01046 ='江西省' AND btjc01047 ='九江市' AND btjc01048 ='修水縣' AND (beginYearMonth <='2019-10') ) AS mingxi LIMIT 100,200;
執行計划如下所示:
可以看到 執行計划里面出現了 Using intersect,btjc01046 btjc01048 btjc01037 btjc01047 多個索引來進行數據的過濾。
另外發現一個問題,里面的 union all 子查詢 卻只需要 0.4秒就可以執行完成:
SELECT btjc01.id, department.`name` AS btjc01011, btjc01011 AS obj, btjc01.inibeginmonth AS beginYearMonth, lsbtsj.btje AS btjc01030, CASE WHEN btjc01.inibeginmonth ='2019-10' THEN '是' ELSE '否' END AS isadd FROM btjc01 INNER JOIN department ON department.Id = btjc01.btjc01038 INNER JOIN lsbtsj ON lsbtsj.btrid = btjc01.Id WHERE btjc01.btjc01037 = '3' AND btjc01046 ='江西省' AND btjc01047 ='九江市' AND btjc01048 ='修水縣' AND lsbtsj.btqsyf <='2019-10' AND lsbtsj.btjzyf >='2019-10' AND beginYearMonth != inibeginmonth UNION ALL SELECT btjc01.id, department.`name` AS btjc01011, btjc01011 AS obj, btjc01.beginYearMonth, btjc01.btjc01030, CASE WHEN btjc01.inibeginmonth ='2019-10' THEN '是' ELSE '否' END AS isadd FROM btjc01 INNER JOIN department ON department.Id = btjc01.btjc01038 INNER JOIN btgg03 ON btgg03.Id = btjc01.btjc01040 WHERE btjc01.btjc01037 = '3' AND btjc01046 ='江西省' AND btjc01047 ='九江市' AND btjc01048 ='修水縣' AND (beginYearMonth <='2019-10')
執行計划如下:
比較一下前面和后面兩個的執行計划,可以發現 都是有了 Using intersect 但是呢后面一個卻只需要0.4秒,而在外面加上一層 select * from t,時間卻需要7到8秒。一直沒有明白什么原因。
最后的優化是去掉 Using interset ,使用 force index 手動指定使用索引 btjc01048:
SELECT mingxi.* FROM ( SELECT btjc01.id, department.`name` AS btjc01011, btjc01011 AS obj, btjc01.inibeginmonth AS beginYearMonth, lsbtsj.btje AS btjc01030, CASE WHEN btjc01.inibeginmonth ='2019-10' THEN '是' ELSE '否' END AS isadd FROM btjc01 force index(btjc01048) INNER JOIN department ON department.Id = btjc01.btjc01038 INNER JOIN lsbtsj ON lsbtsj.btrid = btjc01.Id WHERE btjc01.btjc01037 = '3' AND btjc01046 ='江西省' AND btjc01047 ='九江市' AND btjc01048 ='修水縣' AND lsbtsj.btqsyf <='2019-10' AND lsbtsj.btjzyf >='2019-10' AND beginYearMonth != inibeginmonth UNION ALL SELECT btjc01.id, department.`name` AS btjc01011, btjc01011 AS obj, btjc01.beginYearMonth, btjc01.btjc01030, CASE WHEN btjc01.inibeginmonth ='2019-10' THEN '是' ELSE '否' END AS isadd FROM btjc01 force index(btjc01048) INNER JOIN department ON department.Id = btjc01.btjc01038 INNER JOIN btgg03 ON btgg03.Id = btjc01.btjc01040 WHERE btjc01.btjc01037 = '3' AND btjc01046 ='江西省' AND btjc01047 ='九江市' AND btjc01048 ='修水縣' AND (beginYearMonth <='2019-10') ) AS mingxi LIMIT 100,200;
執行時間需要1.2秒左右,和0.4秒相比,還是有差距。執行計划如下;
可以看到沒有了 Using interset. 我們強制使用索引 btjc01048.
總結:
如果出現 Using interset 需要注意是否mysql優化器選擇的是否是最佳的索引方案。是否可以通過force index來選擇更優的索引。