现场反馈有一个sql执行很慢,拿到sql,简化如下所示:
SELECT
sjlz.C_AJBS
FROM
db_yw.xxx sjlz
INNER JOIN (
SELECT
CONCAT(
zt.xx,
zt.xx,
DATE_FORMAT( zt.DT_FSSJ, '%Y%m%d%H%i%s' )) AS cWybs,
zt.C_BH
FROM
db_ajm.xx zt
WHERE
x1 NOT LIKE '%22%22%'
OR x1 IS NULL
LIMIT 0,
1000
) temp ON sjlz.C_AJBS = temp.cWybs
分析sql, 该sql就是二张表进行inner join ,其中sjlz表是被驱动表,temp表为驱动表。
分析过程
- join 之间的优化就在于驱动表和被驱动表,驱动表要设置为小表并且被驱动表应该在关联字段添加索引。
默认的话,驱动表应该是左表,但是mysql会优化,因此会选表小的作为驱动表,因此这里的temp子查询的表就是小表了,sjlz表就是被驱动表了,检查发现sjlz的C_AJBS是添加了索引了。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ScRdZDOB-1650421393967)(2)]
- 执行explain
也证实了想法,驱动表是temp,被驱动表是sjlz,但是sjlz不走索引,而是进行笛卡尔积的join操作,并且sjlz表大,导致使用了join buffer。
-
为啥不走索引呢?
- 考虑回表操作,我特意将查询列换成索引列,也不存在回表,因此也不存在说回表导致不走索引
- 考虑索引长度,看索引也没有截取长度
-
考虑字符集编码
二个表是属于不同模式下的表,因此可能会存在字符集不相同,
让运维人员查看了现场环境的sjlz编码,发现确实不一样,sjlz编码是utf, 另一张表编码是uftmb4,因此不走索引是因为字符编码不同所导致。 -
证实
修改表的字符集都为utf8, 执行explain ,ext就显示 using where ; using index;