为什么 EXISTS(NOT EXIST) 与 JOIN(LEFT JOIN) 的性能会比 IN(NOT IN) 好

 

前言

网络上有大量的资料提及将 IN 改成 JOIN 或者 exist,然后修改完成之后确实变快了,可是为什么会变快呢?IN、EXIST、JOIN 在 MySQL 中的实现逻辑如何理解呢?本文也是比较粗浅的做一些介绍,知道了 MySQL 的大概执行逻辑,也方便理解。本书绝大多数内容来自:高性能MySQL第三版(O'Reilly.High.Performance.MySQL.3rd.Edition.M),还有一部分来自于网络,还有的来自于自己的理解,以下的内容有引用的都会做标准,如有雷同,纯属巧合。

IN 改为 JOIN/EXIST

例如有如下的 IN 查询:

SELECT     *  FROM     tbl1  WHERE     col3 IN ( SELECT col3 FROM tbl2 )

如果子查询 select id from t2 数据量比较大的情况下,则会很慢,从网络找找答案,就知道往往是建议修改为:

SELECT     *  FROM     tbl1  WHERE     EXISTS ( SELECT 1 FROM tbl2 WHERE tbl1.col3 = tbl2.col3 )

或者改成 INNER JOIN 形式:

SELECT     *  FROM     tbl1     INNER JOIN tbl2 ON tbl1.col3 = tbl2.col3

确实这两种优化是可行的。不过总体来说更推荐 INNER JOIN,下面章节也会提及。

MySQL JOIN 语法的执行逻辑

一下内容摘抄自 高性能MySQL第三版(O'Reilly.High.Performance.MySQL.3rd.Edition.M),文章目录:Query Performance Optimization-->Query Execution Basics-->The Query optimizer Process-->MySQL's join execution strategy

INNER JOIN

简单的 JOIN 例子:

SELECT     tbl1.col1,     tbl2.col2  FROM     tbl1 INNER JOIN tbl2 USING ( col3 )  WHERE     tbl1.col1 IN ( 5, 6 );

MySQL 执行的伪代码:

// WHERE tbl1.col1 IN ( 5, 6 ) 筛选出 tb11 符合条件的记录 outer_iter = iterator over tbl1 where col1 IN(5,6) outer_row = outer_iter.next while outer_row     // 用 tb11 的 col3 去 tbl2 表中查询,有索引将会非常快     inner_iter = iterator over tbl2 where col3 = outer_row.col3     inner_row = inner_iter.next     // 可能会命中多条数据     while inner_row         output [ outer_row.col1, inner_row.col2 ]         inner_row = inner_iter.next     end     outer_row = outer_iter.next end

实际上就是两个循环啦,从上面的代码可以大致了解到,为什么等连接加了索引会很快,主要是因为加了索引,这条语句将走索引:inner_iter = iterator over tbl2 where col3 = outer_row.col3

LEFT JOIN

简单的例子:

SELECT     tbl1.col1,     tbl2.col2  FROM     tbl1     LEFT OUTER JOIN tbl2 USING ( col3 )  WHERE     tbl1.col1 IN ( 5, 6 );

MySQL 执行的伪代码:

// WHERE tbl1.col1 IN ( 5, 6 ) 筛选出 tb11 符合条件的记录 outer_iter = iterator over tbl1 where col1 IN(5,6) outer_row = outer_iter.next while outer_row     // 用 tb11 的 col3 去 tbl2 表中查询,有索引将会非常快     inner_iter = iterator over tbl2 where col3 = outer_row.col3     inner_row = inner_iter.next     if inner_row         // 可能会命中多条数据         while inner_row             output [ outer_row.col1, inner_row.col2 ]             inner_row = inner_iter.next         end     else         // 没有命中的则返回 NULL         output [ outer_row.col1, NULL ]     end     outer_row = outer_iter.next end

关键字:
50000+
5万行代码练就真实本领
17年
创办于2008年老牌培训机构
1000+
合作企业
98%
就业率

联系我们

电话咨询

0532-85025005

扫码添加微信