天天看点

MySQL优化案例:半连接(semi join)优化方式导致的查询性能低下

MySQL优化案例:半连接(semi join)优化方式导致的查询性能低下

以下是来自dba+社群mysql领域原创专家李海翔分享的mysql优化案例,关于mysql v5.6.x/5.7.x sql查询性能问题。

专家简介

MySQL优化案例:半连接(semi join)优化方式导致的查询性能低下

李海翔

网名:那海蓝蓝

dba+社群mysql领域原创专家

从事数据库研发、数据库测试与技术管理等工作10余年,对数据库的内核有深入研究,擅长于postgresql和mysql等开源数据库的内核与架构。现任职于oracle公司mysql全球开发团队,从事查询优化技术的研究和mysql查询优化器的开发工作。著有《数据库查询优化器的艺术》一书。

一、简单创建一表,并使用存储过程插入一部分数据

MySQL优化案例:半连接(semi join)优化方式导致的查询性能低下

二、执行如下查询

q1:

MySQL优化案例:半连接(semi join)优化方式导致的查询性能低下

q2:q2比q1只多了一个使用or子句连接的条件,数据中没有满足此条件的数据

MySQL优化案例:半连接(semi join)优化方式导致的查询性能低下

问题:  q1和q2哪个查询快?快者比慢者能快出几倍?为什么?

三、实际运行结果

对q1和q2稍加改造,目的是避免有大量的查询结果输出。目标列使用count()函数替换。

MySQL优化案例:半连接(semi join)优化方式导致的查询性能低下

看红色字体,所耗费的时间,q1是q2的近乎40倍。为什么?

四、探索原因

第一招:察看执行计划

MySQL优化案例:半连接(semi join)优化方式导致的查询性能低下

对比执行计划,发现q1使用了“materialized”物化方式存储子查询的临时结果,是不是物化导致了q1慢呢?

第二招:察看io

MySQL优化案例:半连接(semi join)优化方式导致的查询性能低下
MySQL优化案例:半连接(semi join)优化方式导致的查询性能低下
MySQL优化案例:半连接(semi join)优化方式导致的查询性能低下

q2和q1不一致之处在于q2的“handler_read_key”值20002远远比比q1的2高,这说明q2更多地利用了索引。

且看mysql官方解释如下:

handler_read_key

the number of requests to read a row based on a key. if this value is high, it is a good indication that your tables are properly indexed for your queries.

问题:

为什么q2会有更多的索引读?索引是从哪里来的?

q1被物化,意味着q1使用了临时表;而q2子查询是否被物化是否使用了临时表呢?

五、新的疑问,再次探索

之下如下操作,注意show warnings技巧的使用。查询结果作了形式的调整,便于阅读。

MySQL优化案例:半连接(semi join)优化方式导致的查询性能低下

可以看出,q1的子查询被物化后,又作了半连接优化,意味着子查询被上拉方式优化。

MySQL优化案例:半连接(semi join)优化方式导致的查询性能低下
MySQL优化案例:半连接(semi join)优化方式导致的查询性能低下

q2表明,首先使用了临时表,但是和q1不同的是,子查询没有被上拉优化。

但是,mysql对于临时表的使用,会自动创建索引,所以我们能看到在“auto_key”上执行了“primary_index_lookup”。这就是q2快于q1的原因。也是为什么q2的索引读计数器的值较大的原因。

问题:半连接优化

六、继续探索

MySQL优化案例:半连接(semi join)优化方式导致的查询性能低下

执行计划似乎改变不大,但类似了q2的执行计划。(哈哈,可执行show warnings;命令看看,获取更详细的信息才能得出更靠谱的结论)

MySQL优化案例:半连接(semi join)优化方式导致的查询性能低下

在禁止了半连接操作之后,执行速度一下子坐上了飞机,有了40余倍的提升。

七、结论

1. q1使用了物化+半连接优化,q2是子查询,但没有使用半连接优化,可见mysql中半连接优化的效率未必高。

2. 似乎物化的子查询用半连接上拉,mysql的判断条件还是存在一点儿问题。

<b></b>

<b>本文来自云栖社区合作伙伴"dbaplus",原文发布时间:2015-12-07</b>