MySQL:内部联接与 Where [重复]

Posted

技术标签:

【中文标题】MySQL:内部联接与 Where [重复]【英文标题】:MySQL: Inner join vs Where [duplicate] 【发布时间】:2011-07-13 12:51:52 【问题描述】:

两者之间的性能(在mysql中)是否存在差异

Select * from Table1 T1 
Inner Join Table2 T2 On T1.ID = T2.ID

Select * from Table1 T1, Table2 T2 
Where T1.ID = T2.ID

?

【问题讨论】:

重复***.com/questions/44917/… 【参考方案1】:

我的一个迟到的答案,因为我正在分析使用基于逗号的连接而不是 INNER JOIN 子句的旧应用程序的性能。

所以这里有两个表,它们有一个连接(两个表的记录都超过 1 lac)。执行具有基于逗号连接的查询时,它比INNER JOIN 的情况要长得多。

当我分析解释语句时,我发现有逗号连接的查询正在使用连接缓冲区。但是,具有INNER JOIN 子句的查询具有“使用Where”。

这些查询也有很大的不同,如解释查询中的行列所示。 这些是我的查询及其各自的解释结果。

explain select count(*) FROM mbst a , his_moneypv2 b 
        WHERE b.yymm IN ('200802','200811','201001','201002','201003') 
        AND a.tel3 != '' 
        AND a.mb_no = b.mb_no 
        AND b.true_grade_class IN (3,6)
        OR b.grade_class IN (4,7);

+----+-------------+-------+-------------+----------------------------------------------------------------+--------------------------------------+---------+------+--------+---------------------------------------------------------------------+
| id | select_type | table | type        | possible_keys                                                  | key                                  | key_len | ref  | rows   | Extra                                                               |
+----+-------------+-------+-------------+----------------------------------------------------------------+--------------------------------------+---------+------+--------+---------------------------------------------------------------------+
|  1 | SIMPLE      | b     | index_merge | PRIMARY,mb_no,yymm,yymm_2,idx_true_grade_class,idx_grade_class | idx_true_grade_class,idx_grade_class | 5,9     | NULL |  16924 | Using sort_union(idx_true_grade_class,idx_grade_class); Using where |
|  1 | SIMPLE      | a     | ALL         | PRIMARY                                                        | NULL                                 | NULL    | NULL | 134472 | Using where; Using join buffer                                      |
+----+-------------+-------+-------------+----------------------------------------------------------------+--------------------------------------+---------+------+--------+---------------------------------------------------------------------+

v/s

explain select count(*) FROM mbst a inner join his_moneypv2 b 
        on a.mb_no = b.mb_no 
        WHERE b.yymm IN ('200802','200811','201001','201002','201003') 
        AND a.tel3 != '' 
        AND b.true_grade_class IN (3,6) 
        OR b.grade_class IN (4,7);

 +----+-------------+-------+-------------+----------------------------------------------------------------+--------------------------------------+---------+--------------------+-------+---------------------------------------------------------------------+
 | id | select_type | table | type        | possible_keys                                                  | key                                  | key_len | ref                | rows  | Extra                                                               |
 +----+-------------+-------+-------------+----------------------------------------------------------------+--------------------------------------+---------+--------------------+-------+---------------------------------------------------------------------+
 |  1 | SIMPLE      | b     | index_merge | PRIMARY,mb_no,yymm,yymm_2,idx_true_grade_class,idx_grade_class | idx_true_grade_class,idx_grade_class | 5,9     | NULL               | 16924 | Using sort_union(idx_true_grade_class,idx_grade_class); Using where |
 |  1 | SIMPLE      | a     | eq_ref      | PRIMARY                                                        | PRIMARY                              | 62      | shaklee_my.b.mb_no |     1 | Using where                                                         |
 +----+-------------+-------+-------------+----------------------------------------------------------------+--------------------------------------+---------+--------------------+------

【讨论】:

经过更多分析,我发现两个查询之间的巨大性能差异是由两个约束造成的。在任何其他过滤条件之前,第一个连接条件必须是 where 子句中的第一个。第二次使用括号对具有或的语句进行分组 您的查询没有返回相同的行。带有b.grade_class IN (4,7) 的交叉连接行总是在第一个from 的输出中,但是当a.mb_no = b.mb_no 时它们不在第二个from 的输出中。因此,比较查询不会告诉您有关问题的任何信息。【参考方案2】:

它们是一样的。这可以通过运行EXPLAIN 命令看到:

mysql> 解释 Select * from Table1 T1 -> Inner Join Table2 T2 On T1.ID = T2.ID; +----+-------------+--------+-------+-------------- -+---------+---------+------+------+-------------- -----------------------------------------------+ |编号 |选择类型 |表|类型 |可能的键 |关键 | key_len |参考 |行 |额外 | +----+-------------+--------+-------+-------------- -+---------+---------+------+------+-------------- -----------------------------------------------+ | 1 |简单 | T1 |索引 |初级 |初级 | 4 |空 | 4 |使用索引 | | 1 |简单 | T2 |索引 |初级 |初级 | 4 |空 | 4 |使用哪里;使用索引;使用连接缓冲区 | +----+-------------+--------+-------+-------------- -+---------+---------+------+------+-------------- -----------------------------------------------+ 2 行(0.00 秒) mysql> explain Select * from Table1 T1, Table2 T2 -> 其中 T1.ID = T2.ID; +----+-------------+--------+-------+-------------- -+---------+---------+------+------+-------------- -----------------------------------------------+ |编号 |选择类型 |表|类型 |可能的键 |关键 | key_len |参考 |行 |额外 | +----+-------------+--------+-------+-------------- -+---------+---------+------+------+-------------- -----------------------------------------------+ | 1 |简单 | T1 |索引 |初级 |初级 | 4 |空 | 4 |使用索引 | | 1 |简单 | T2 |索引 |初级 |初级 | 4 |空 | 4 |使用哪里;使用索引;使用连接缓冲区 | +----+-------------+--------+-------+-------------- -+---------+---------+------+------+-------------- -----------------------------------------------+ 2 行(0.00 秒)

【讨论】:

【参考方案3】:

第一个查询对于 MySQL 来说更容易理解,因此执行计划可能会更好,并且查询会运行得更快。

没有 where 子句的第二个查询是交叉连接。如果 MySQL 能够很好地理解 where 子句,它会尽量避免交叉连接所有行,但不能保证这一点。

在像您这样简单的情况下,性能将完全相同。

在性能方面,第一个查询总是比第二个更好或相同。而且从我的角度来看,重读时也更容易理解。

【讨论】:

【参考方案4】:

实际上它们几乎相同,JOIN / ON 是较新的 ANSI 语法,WHERE 是较旧的 ANSI 语法。两者都被查询引擎识别

【讨论】:

【参考方案5】:

第二个查询只是内连接的另一种表示法,所以如果在性能上存在差异,那只是因为一个查询的解析速度比另一个查询快 - 如果存在差异,那么差异将非常小,以至于你不会注意到的。

有关更多信息,您可以尝试查看this question(并在下次询问已回答的问题之前使用 SO 上的搜索)

【讨论】:

【参考方案6】:

从问题 44917 中接受的答案中得出:

在性能方面,它们正是 相同(至少在 SQL Server 中)但是是 意识到他们正在弃用 隐式外连接语法。

在 MySql 中结果是一样的。

我个人会坚持明确加入表格...这是“社会可接受的”方式。

【讨论】:

我为 Oracle 找到了相同的答案,并且有些人同意执行没有区别。对于 Oracle,有一种方法可以检查查询的“计划”,MySQL 中是否有类似的东西? 这取决于您的软件。您在为 MySql 使用什么... Toad for MySQL 为您创建的任何查询提供了一个“解释计划”选项卡,但它可能并不完全符合您的要求。它使用 Ewan 在他的回答中提到的“EXPLAIN”命令。 我同意显式 JOIN 更好。实际上,如果您忘记了 WHERE 子句的某些部分,它更安全,并且不太容易成为 CROSS JOIN。 我相信使用JOIN更容易维护代码。它更具可读性。我只会使用 CROSS JOIN 来提高性能。 “社会可接受”深入人心。【参考方案7】:

我会这样认为,因为第一个示例明确告诉 mysql 要加入哪些列以及如何加入它们,第二个 mysql 必须尝试找出您要加入的位置。

【讨论】:

【参考方案8】:

FROM 子句中的逗号是 CROSS JOIN。我们可以想象 SQL Server 有一个选择查询执行过程,它看起来应该是这样的: 1.遍历每个表 2. 找到满足连接谓词的行并将其放入结果表中。 3. 从结果表中,只获取满足where条件的行。

如果看起来确实如此,那么在检查 where 条件之前,在每行相互组合时,对具有数千行的表使用 CROSS JOIN 可能会分配大量内存。那时您的 SQL 服务器可能会很忙。

【讨论】:

我不认为它是这样工作的。如果是这样,如果 where 条件将第一个表过滤为仅一条记录,那么它只会将一条记录与第二个表合并,从而使其非常快?我相信 SQL 以其他方式处理数据(我只能猜测)。

以上是关于MySQL:内部联接与 Where [重复]的主要内容,如果未能解决你的问题,请参考以下文章

使用内部联接删除一行数据[重复]

MySQL如何使用仅用于计数的where子句计算左联接?

具有内部联接的重复列

添加内部联接使查询显示重复

mysql连接内连接左连接右连接全连接

MySQL内部联接返回同一行的倍数