今天遇到一个sql查询很慢,在客户的uat环境,查询要25s 查询语句如下(大概是这个样子)

SELECT
  t1.xxx,
  t2.xxx,
  t3.xxx,
  t3.xbx,
  ...
FROM
  tab_1 t1
  JOIN tab_2 t2 ON t1.id = t2.t1_id AND t2.flag = 1 AND t2.record_status = 1
  JOIN tab_3 t3 ON t2.id = t3.t1_id AND t3.flag = 1 AND t3.record_status = 1
  JOIN tab_4 t4 ON t3.id = t4.t1_id AND t4.flag = 1 AND t4.record_status = 1
  JOIN tab_5 t5 ON t4.id = t5.t1_id AND t5.flag = 1 AND t5.record_status = 1
  LEFT JOIN tab_6 t6 ON t5.id = t6.t1_id AND t6.flag = 1 AND t6.record_status = 1
  JOIN tab_7 t7 ON t6.t7_code = t7.CODE AND t7.flag = 1 AND t7.record_status = 1 
WHERE
  t1.xxx = xxx 
  AND t2.xxx = xxx 
  AND t3.xx_date > t4.xx_date

遇到查询慢,我先用explain查看了执行计划,而后发现,基本都用上了索引而且数据量也不多。

然后我就想知道到底是哪里慢了。

我先把查询条件去除了,结果查询很快,我就知道,查询条件肯定没用上索引,有可能回表了,也有可能全部扫描了。因为extra那一栏显示的using where,还有Using join buffer (hash join)。说明where并没有用上索引

而后,我又将join的表,一个个删,最终发现是t5,加上t5,查询就很慢。综合执行计划,我就推测,查询优化器给我们选择的索引有可能不是最佳索引。因为我们需要查询的列,还有where条件,都有可能不再查询优化器选择的索引上。查询优化器大概是选择,能用上索引的len最大的那个索引吧(t5的连表,查询优化器选择了一个联合索引,里面有三个字段)。

后来,我将t5的连表,强制使用主键索引,查询瞬间就到毫秒级了。因为主键中拥有所有的字段信息,连表之后,在where也能用上这些信息,这样总比回表好吧,回表要多次回查主键索引。而且我们需要查的列,在主键中肯定也有,索引使用主键可谓是一举两得。至此问题解决