【问题标题】:Why LEFT JOIN increase query time so much?为什么 LEFT JOIN 会增加这么多查询时间?
【发布时间】:2014-03-20 09:02:38
【问题描述】:

我使用的是 SQL Server 2012,遇到了奇怪的问题。

这是我一直使用的原始查询:

DELETE FROM [TABLE_TEMP]

INSERT INTO [TABLE_TEMP]
   SELECT H.*, NULL 
   FROM [TABLE_Accounts_History] H
   INNER JOIN [TABLE_For_Filtering] A ON H.[RSIN] = A.[RSIN]
   WHERE
      H.[NUM] = (SELECT TOP 1 [NUM] FROM [TABLE_Accounts_History]
                 WHERE [RSIN] = H.[RSIN] 
                   AND [AccountSys] = H.[AccountSys]
                   AND [Cl_Acc_Typ] = H.[Cl_Acc_Typ]
                   AND [DATE_DEAL] < @dte
                 ORDER BY [DATE_DEAL] DESC)
      AND H.[TYPE_DEAL] <> 'D'

TABLE_Accounts_History 包含 3 200 000 条记录。

TABLE_For_Filtering 大约有 1 500 条记录。

Insert 花了我 2m 40s 并插入 1 600 000 条记录以供进一步工作。

但后来我决定从非常小的表格TABLE_Additional 中附加一列(仅在 100 左右):

DELETE FROM [TABLE_TEMP]

INSERT INTO [TABLE_TEMP]
   SELECT H.*, P.[prof_type]    
   FROM [TABLE_Accounts_History] H
   INNER JOIN [TABLE_For_Filtering] A ON H.[RSIN] = A.[RSIN]
   LEFT JOIN [TABLE_Additional] P ON H.[ACCOUNTSYS] = P.[AccountSys]
   WHERE        H.[NUM] = ( SELECT TOP 1    [NUM]
                        FROM            [TABLE_Accounts_History]
                        WHERE           [RSIN] = H.[RSIN]
                                    AND [AccountSys] = H.[AccountSys]
                                    AND [Cl_Acc_Typ] = H.[Cl_Acc_Typ]
                                    AND [DATE_DEAL] < @dte
                        ORDER BY        [DATE_DEAL] DESC)
        AND H.[TYPE_DEAL] <> 'D' 

现在这个查询需要很长时间才能完成。为什么会这样?这么小的左连接怎么可能会降低性能?我该如何改进它?

更新:到目前为止,LEFT JOIN 运气不佳。索引,无索引,提示索引.. 现在我通过使用我的第一个查询和之后的 UPDATE 找到了一种解决方法:

UPDATE  [TABLE_TEMP]
SET     [PROF_TYPE] = P1.[prof_type]
FROM    [TABLE_TEMP] A1
LEFT JOIN
        [TABLE_Additional] P1
    ON  A1.[ACCOUNTSYS] = P1.[AccountSys]

只需要 5 秒,并且几乎与我一直在努力实现的目标相同。 SQL Server 的性能对我来说仍然是个谜。

【问题讨论】:

    标签: sql-server join left-join


    【解决方案1】:

    “小”左连接实际上为您做了很多额外的工作。 SQL Server 必须从 TABLE_Accounts_History 和 TABLE_For_Filtering 之间的内部连接返回到 TABLE_Additional。您可以通过尝试一些索引来帮助 SQL Server 一些方法来加快速度。你可以:

    1) 确保 TABLE_Accounts_History 在外键 H.[ACCOUNTSYS] 上有一个索引

    2) 如果您认为 AccountSys 将始终访问 TABLE_Additional,即您将在有序组中请求 AccountSys,您可以在 TABLE_Additional.AccountSys 上创建一个聚集索引。 (换句话说,按照 AccountSys 的顺序对磁盘上的表进行物理排序)

    3) 您还可以确保 TABLE_Accounts_History 上有一个外键索引。

    【讨论】:

    • 我以前一直在这样做,实际上是使用 FROM TABLE_Accounts_History H WITH (INDEX(accounts_h_search1)) 之类的提示。没有成功。另一张桌子也一样。而较小的表实际上有聚集索引。
    • 除非您真的处于高级阶段,否则我会避开表格提示。 SQL Server 有一个称为优化器的框,它决定如何最好地运行您的查询。如果您不知道真正的问题在哪里,手动提示有时会适得其反。如果您在查询分析器中查看查询的执行计划,您应该会看到成本最高的位置。随意在此处附上一张图片,我会尽力弄清楚。
    • 嗯,执行计划很长(水平两个屏幕)所以没有图像,抱歉,但左连接本身的成本为 0%。 TABLE_Accounts_History 上的聚集索引扫描占 11%,同一张表上的非聚集索引扫描占 87%。两者都远在左连接之前。 ACTUAL 执行计划应该有所不同,但我从来没有足够的耐心来完成这个查询。
    • 你能把鼠标悬停在 87% 的东西上截屏吗?这就是关键。
    • 没有足够的代表来发布图片,这是一个链接。对不起,如果您不懂语言,没有英语环境link
    【解决方案2】:

    left outer join 选择左表中的所有行。在您的情况下,您的左表有 3 200 000 这么多行,然后将每条记录与右表进行比较。一种解决方案是使用Indexes,这将减少检索时间。

    【讨论】:

    • 实际上,我正在使用它们。但是这种性能下降以某种方式幸免于难。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-02-21
    • 2017-09-18
    • 1970-01-01
    • 2019-10-09
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多