我应该在SQL Server中嵌套依赖的外部联接吗?


9

我听说过与此相关的信息不一,并希望能提出规范或专家意见。

如果我有多个LEFT OUTER JOIN,每个都依赖于最后一个,嵌套它们会更好吗?

对于一个人为的示例,JOINto MyParent取决于JOINto MyChildhttp : //sqlfiddle.com/#!3/31022/5

SELECT
    {columns}
FROM
    MyGrandChild AS gc
LEFT OUTER JOIN
    MyChild AS c
        ON c.[Id] = gc.[ParentId]
LEFT OUTER JOIN
    MyParent AS p
        ON p.[id] = c.[ParentId]

在此处输入图片说明

http://sqlfiddle.com/#!3/31022/7相比

SELECT
    {columns}
FROM
    MyGrandChild AS gc
LEFT OUTER JOIN
    (
    MyChild AS c            
    LEFT OUTER JOIN
        MyParent AS p
            ON p.[id] = c.[ParentId]
    )
    ON c.[Id] = gc.[ParentId]

在此处输入图片说明

如上所示,这些在SS2k8中产生不同的查询计划


我喜欢使用嵌套联接:michaeljswart.com/2012/09/when-i-use-nested-joins虽然可能是样式问题。
Michael J Swart

@MichaelJSwart您的博客仅在讨论受抚养人JOIN是何时INNER JOIN
Matthew

1
您如何定义“更好”?就我个人而言,我发现第一个更容易阅读-我的想法并没有围绕尝试反向关系而反弹。有ON ... ON一排(括号或不)两次非常混乱。
亚伦·伯特兰

4
当我发现两种做事方式之间没有性能差异时,我要问自己的下一个问题是:如果我今晚乘公交车或中了彩票,明天接管我的代码的人最容易理解和维护哪个版本?
亚伦·伯特兰

1
use plan第二个查询计划移植到第一个查询计划时,提示起作用,反之亦然。
马丁·史密斯

Answers:


3

这绝对不是一个规范的答案,但是我注意到,对于SQL Fiddle中显示的嵌套循环查询计划,可以通过使用提示将计划从Query 2应用于Query 1,USE PLAN但是尝试反向操作会失败

查询处理器无法生成查询计划,因为USE PLAN提示包含无法验证为合法查询的计划。删除或替换USE PLAN提示。为了最大可能地成功执行计划,请验证USE PLAN提示中提供的计划是否是SQL Server为同一查询自动生成的计划。

禁用优化器转换规则 ReorderLOJN也会阻止先前成功的计划提示也成功。

对大量数据进行的实验表明,SQL Server当然也可以转换(A LOJ B) LOJ CA LOJ (B LOJ C)自然数据,但是我没有看到任何证据表明事实相反。

第一个查询的性能比第二个查询好的一个非常人为的情况是

DROP TABLE  MyGrandChild , MyChild,  MyParent

CREATE TABLE MyParent
(Id int)

CREATE TABLE MyChild
(Id int PRIMARY KEY
,ParentId int,
Filler char(8000) NULL)

CREATE TABLE MyGrandChild
(Id int
,ParentId int)

INSERT INTO MyChild
                      (Id, ParentId)
SELECT TOP (100000) ROW_NUMBER() OVER (ORDER BY @@SPID),
                     ROW_NUMBER() OVER (ORDER BY @@SPID)    
FROM master..spt_values  v1, master..spt_values                  

INSERT INTO MyGrandChild
                      (Id, ParentId)
OUTPUT INSERTED.Id INTO MyParent
SELECT TOP (3000) Id, Id AS ParentId
FROM MyChild
ORDER BY Id

SET STATISTICS IO ON;
SET STATISTICS TIME ON;

SELECT gc.Id       AS gcId,
       gc.ParentId AS gcpId,
       c.Id        AS cId,
       c.ParentId  AS cpId,
       p.Id        AS pId
FROM   MyGrandChild AS gc
       LEFT OUTER JOIN MyChild AS c
         ON c.[Id] = gc.[ParentId]
       LEFT OUTER JOIN MyParent AS p
         ON p.[Id] = c.[ParentId]

SELECT gc.Id       AS gcId,
       gc.ParentId AS gcpId,
       c.Id        AS cId,
       c.ParentId  AS cpId,
       p.Id        AS pId
FROM   MyGrandChild AS gc
       LEFT OUTER JOIN( MyChild AS c
                        LEFT OUTER JOIN MyParent AS p
                          ON p.[Id] = c.[ParentId])
         ON c.[Id] = gc.[ParentId] 

给出计划

在此处输入图片说明

对我来说,查询1的经过时间为108毫秒,而查询2的经过时间为1,163毫秒。

查询1

Table 'Worktable'. Scan count 0, logical reads 0 
Table 'MyChild'. Scan count 0, logical reads 9196
Table 'MyGrandChild'. Scan count 1, logical reads 7
Table 'MyParent'. Scan count 1, logical reads 5

查询2

Table 'MyParent'. Scan count 1, logical reads 15000
Table 'MyChild'. Scan count 0, logical reads 9000 
Table 'MyGrandChild'. Scan count 1, logical reads 7

因此,可以暂时假定第一种(“未嵌套的”)语法是潜在的好处,因为它允许考虑更多潜在的加入顺序,但是作为一般规则,我没有进行详尽的测试以对它有很大的信心。

完全有可能提出查询2性能更好的反例。尝试两者并查看执行计划。


-1

没有这样的JOIN类型,称为“嵌套联接”。这是编写JOIN的另一种形式,可能是为了便于阅读。您只能将它们视为“子查询”,仅用于理解目的。

如果您更关心代码的可读性,那么我想的是,由他们自己决定使用哪种代码。

并且,如果您担心查询的性能,并且查询中未使用“ Force JOIN ORDER”提示,则查询写的是“嵌套联接”还是“所有外部联接”都没有关系。SQL Server根据联接两个表的成本和/或结果得出命令。SQL Server一次仅在两组数据之间执行JOIN。

实际上,想象一下,如果SQL Server决定执行第二部分,则以第二种方式“嵌套联接”,即“ MyChild AS c左外部联接MyParent AS p ON p。[id] = c。[ParentId]”,并且这些表就会出现在NEXT LEFT JOIN中有要丢弃的行。在那种情况下,SQL Server在执行这两个外部联接并将结果传递给下一个联接时花费了不必要的资源。

您也可以在此处适当地询问类似的问题。 了解“嵌套连接”语法


1
那么,为什么他们不使用FORCE JOIN ORDER提示就产生不同的查询计划呢?
马修

没有该提示,我们不能保证加入的顺序,并且您看到的另一种执行计划证明了这一点。例如,以第一种方式“使用所有外部联接” SQL Server可能会执行这两个操作中的任何一个。首先“ MyChild + MyGrandChild”,然后加入“ MyParent”。或首先“ MyChild + MyParent”,然后加入“ MyGrandChild”。
Anup Shah 2014年
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.