首页 > 解决方案 > 使用两个连接到同一个表的慢速执行 T-SQL 查询

问题描述

我正在努力弄清楚下面显示的 T-SQL 查询发生了什么。

您将看到同一个表的两个内部连接,尽管连接条件不同。第一个连接本身运行大约 21 秒,如果我自己运行第二个连接,它会在大约 27 秒内完成。

如果我将两个连接都保留在原位,则查询将运行并运行,直到我最终停止查询。适当的索引似乎已经到位,我知道这个查询在不同的环境中运行,马力较小,唯一的区别是另一台服务器正在运行 SQL Server 2012,而我正在运行 SQL Server 2016,尽管数据库处于 2012 兼容模式:

此连接在约 21 秒内运行。

SELECT
    COUNT(*)
FROM 
    dbo.SPONSORSHIP as s
INNER JOIN 
    dbo.SPONSORSHIPTRANSACTION AS st 
        ON st.SPONSORSHIPCOMMITMENTID = s.SPONSORSHIPCOMMITMENTID
        AND st.TRANSACTIONSEQUENCE = (SELECT MIN(TRANSACTIONSEQUENCE)
                                      FROM dbo.SPONSORSHIPTRANSACTION AS ms
                                      WHERE ms.SPONSORSHIPCOMMITMENTID = s.SPONSORSHIPCOMMITMENTID
                                        AND ms.TARGETSPONSORSHIPID = s.ID)

此连接在约 27 秒内运行。

SELECT
    COUNT(*) 
FROM
    dbo.SPONSORSHIP AS s
INNER JOIN 
    dbo.SPONSORSHIPTRANSACTION AS lt ON lt.SPONSORSHIPCOMMITMENTID = s.SPONSORSHIPCOMMITMENTID 
        AND lt.TRANSACTIONSEQUENCE = (SELECT MAX(TRANSACTIONSEQUENCE) 
                                      FROM dbo.SPONSORSHIPTRANSACTION AS ms 
                                      WHERE ms.SPONSORSHIPCOMMITMENTID = s.SPONSORSHIPCOMMITMENTID 
                                        AND s.ID IN (ms.CONTEXTSPONSORSHIPID, 
                                                     ms.TARGETSPONSORSHIPID, 
                                                     ms.DECLINEDSPONSORSHIPID) 
                                        AND ms.ACTIONCODE <> 9)

标签: sql-serverperformancetsqlindexinginner-join

解决方案


这些都被认为是相关的子查询。您通常应该避免这种模式,因为它会导致所谓的“RBAR”......这是“Row by Agonizing Row”。在您专注于解决此特定查询之前,我建议您重新访问查询本身,看看您是否可以通过更基于集合的方法解决此问题。您会发现,在大多数情况下,您还有其他方法可以实现这一目标并显着降低成本。

举个例子:

select
    total_count
    ,row_sequence
from 
    ( 
    SELECT
    total_count = COUNT(*)
    ,row_sequence = row_number() over(order by st.TRANSACTIONSEQUENCE asc)
    FROM 
        dbo.SPONSORSHIP as s
    INNER JOIN dbo.SPONSORSHIPTRANSACTION AS st
    ON st.SPONSORSHIPCOMMITMENTID = s.SPONSORSHIPCOMMITMENTID
) as x
where
    x.row_sequence = 1

这是一个未经测试的简单示例。为了将来参考,如果您想要最佳答案,最好生成一个可以使用的临时表或测试数据集,以便有人可以提供完整的工作示例。

我给出的示例显示了所谓的窗口函数。当您看到单词序列、需要组中的第一个/最后一个等等时,请仔细查看它们以帮助选择结果。

希望这能给你一些想法!欢迎来到堆栈溢出!


推荐阅读