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
命令看到:
【讨论】:
【参考方案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 [重复]的主要内容,如果未能解决你的问题,请参考以下文章