内部联接与内部联接(SELECT . FROM)

Posted

技术标签:

【中文标题】内部联接与内部联接(SELECT . FROM)【英文标题】:INNER JOIN vs INNER JOIN (SELECT . FROM) 【发布时间】:2012-07-19 10:34:22 【问题描述】:

同一查询的这两个版本在性能方面有什么不同吗?

--Version 1
SELECT p.Name, s.OrderQty
FROM Product p
INNER JOIN SalesOrderDetail s on p.ProductID = s.ProductID

--Version 2
SELECT p.Name, s.OrderQty
FROM Product p
INNER JOIN (SELECT ProductID, OrderQty FROM SalesOrderDetail) s on p.ProductID = s.ProductID

我听说(由 DBA)说版本 2 更快,因为它在内部 SELECT 语句中只获取查询所需的列。但这似乎没有意义,因为查询性能(据我所知)基于受影响的行数和返回的最终列列表。

两者的查询计划是相同的,所以我猜两者之间没有任何区别。

我说的对吗?

【问题讨论】:

解雇那个 DBA... 当然,他是不对的。我唯一的解释是他有这个观点,因为一些旧版本的 sql-server 或一些 SP 或 CU 甚至可能是另一个服务器。 实际上,在 mysql 中,这 可以 为真(子选择可以通过强制访问顺序从根本上提高性能)。可怕,我知道。以及为什么我会像瘟疫一样永远避免使用 MySql。 @ErikE:嗯。在讨论 SQL 时,MySql 确实总是很奇怪,不是吗? :-) 根据 PostgreSQL 9.5.6 的解释,INNER JOIN table 将获取所有列,而INNER JOIN (SELECT column1, column2, ...) 将仅获取指定列并且数据宽度小于第一个列。但这仅适用于 PostgreSQL 9.5.6 而不是您的。解雇那个 DBA:P 【参考方案1】:

你是对的。你做了完全正确的事,检查查询计划而不是试图事后猜测优化器。 :-)

【讨论】:

【参考方案2】:

不会有太大区别。但是,当您有一些计算、聚合等应该在它之外加入时,版本 2 会更容易

--Version 2 
SELECT p.Name, s.OrderQty 
FROM Product p 
INNER JOIN 
(SELECT ProductID, SUM(OrderQty) as OrderQty FROM SalesOrderDetail GROUP BY ProductID
HAVING SUM(OrderQty) >1000) s 
on p.ProductID = s.ProdctId 

【讨论】:

是的,我知道当涉及计算或聚合时,这种方法更容易,但我的问题是针对我提出的案例的。谢谢! 你能解释一下吗,如果我使用:SELECT p.Name, s.OrderQty FROM Product p INNER JOIN SalesOrderDetail s on p.ProductID = s.ProductID GROUP BY p.Name HAVING SUM(s.OrderQty) > 1000;提前致谢!【参考方案3】:

似乎是相同的,以防 SQL 服务器不会尝试读取查询不需要的数据,优化器足够聪明

在复杂查询(即本身具有连接、分组等)上连接时可能有意义,然后,是的,最好指定必填字段。

但还有一点。 如果查询很简单,则没有区别,但即使是应该提高性能的每一个额外操作都会使优化器更加努力地工作,并且优化器可能无法及时获得最佳计划,并且不会运行最佳查询。所以 extras select 可能是这样一个甚至会降低性能的操作

【讨论】:

【参考方案4】:

您通过检查查询计划做了正确的事。但我对第 2 版有 100% 的信心。当关闭记录数很高时,它会更快。

我的数据库有大约 1,000,000 条记录,这正是查询计划显示两个查询之间差异的场景。 此外,如果您在连接本身中使用它,而不是使用 where 子句,它会使查询更快: 选择 p.Name、s.OrderQty FROM 产品 p INNER JOIN (SELECT ProductID, OrderQty FROM SalesOrderDetail) s on p.ProductID = s.ProductID WHERE p.isactive = 1

这个查询的更好版本是:

选择 p.Name、s.OrderQty FROM 产品 p INNER JOIN (SELECT ProductID, OrderQty FROM SalesOrderDetail) s on p.ProductID = s.ProductID AND p.isactive = 1

(假设 isactive 是产品表中的一个字段,表示活跃/非活跃产品)。

【讨论】:

-1 SQL Server 可以轻松地将第一个转换为第二个。如果您可以提供一个可重现的测试用例,而它不能(而不仅仅是一个断言),我会很乐意将其反转! 你说得对,Martin,INNER JOIN 的效果是不可见的,但是对于外连接它是可见的。显然,内连接在这两种情况下都是一样的。由于机密性问题,我无法提供我的数据库的快照,但这就是我所说的:blog.sqlauthority.com/2009/03/15/… 您提到的那个博客与结果集有关,与性能无关,当您在 where 子句的左连接中对右表设置一些条件时也是如此。

以上是关于内部联接与内部联接(SELECT . FROM)的主要内容,如果未能解决你的问题,请参考以下文章

在多列上组合 sql 内部和外部联接

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

特定列上的SQL内部联接

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

如何将子查询包含到内部联接中?

使用多个内部联接时,与使用单个内部联接时相比,我得到不同的结果