Table IN 谓词上的扫描和 Eager 假脱机

Table Scan and Eager Spools on IN Predicate

我正在 运行 宁我认为是一个相当简单的查询,但我在查询中遇到了非常糟糕的 return 次。当 运行 查询时,在 IN 谓词中作为过滤器的子查询在用作查询的一部分时正在执行索引扫描和索引假脱机,但 运行 是一个索引在 IN 谓词之外使用时查找。我不知道为什么,但是查询需要将近 30 秒才能 return 零条记录...

查询如下:

SELECT DISTINCT
    C.County
    , S.State
    , C.County_ID
FROM
    Leads L 
    INNER JOIN Inventory I ON L.Deleted = 0 AND L.Inv_ID = I.Inv_ID
    INNER JOIN County C ON C.County_ID = I.County_ID
    INNER JOIN State S ON C.State_ID = S.State_ID AND S.Active = 1
    INNER JOIN Contacts ON L.Contact_ID = Contacts.ID AND Contacts.Deleted = 0
WHERE
    L.Acct_ID = 204940
    OR L.Acct_ID IN (
        SELECT Accounts.Acct_ID FROM Accounts (NOLOCK) WHERE Accounts.Parent_Acct_ID = 204940
    )
ORDER BY
    S.State
    , C.County

这是该查询执行计划的相关部分。 运行正在对 WHERE 子句中的帐户 table 进行扫描,估计要 returned 的行数超过 260,000。子select实际上return有0条记录。

当我 运行 在上述查询之外的那个简单 select 时,我得到了一个直接的索引查找,针对完全相同的索引。 subselect returns 0条记录。如果我 运行 没有 OR 语句的查询我得到 ms 响应时间,如果我 运行 带有 OR 语句的查询,查询需要将近 30 秒才能完成。

这是用于帐户扫描和搜索的索引table(我知道,这是一个 dta 索引,不是我的原始数据库...)

CREATE NONCLUSTERED INDEX [_dta_index_Accounts_5_144719568__K32_50] ON [dbo].[Accounts] 
(
    [parent_Acct_ID] ASC
)
INCLUDE ( [CompanyState]) WITH (PAD_INDEX  = OFF, STATISTICS_NORECOMPUTE  = OFF, SORT_IN_TEMPDB = OFF, IGNORE_DUP_KEY = OFF, DROP_EXISTING = OFF, ONLINE = OFF, ALLOW_ROW_LOCKS  = ON, ALLOW_PAGE_LOCKS  = ON) ON [PRIMARY]
GO

如何在任何合理的时间内将子select 变为 运行 索引查找而不是扫描,以及 return?

试试这个:

   SELECT DISTINCT
        C.County
        , S.State
        , C.County_ID
    FROM
        Leads L 
        INNER JOIN Inventory I ON L.Deleted = 0 AND L.Inv_ID = I.Inv_ID (AND  L.Acct_ID = 204940
        OR L.Acct_ID IN (
            SELECT Accounts.Acct_ID FROM Accounts (NOLOCK) WHERE Accounts.Parent_Acct_ID = 204940
        ))
        INNER JOIN County C ON C.County_ID = I.County_ID
        INNER JOIN State S ON C.State_ID = S.State_ID AND S.Active = 1
        INNER JOIN Contacts ON L.Contact_ID = Contacts.ID AND Contacts.Deleted = 0
    ORDER BY
        S.State
        , C.County

我稍微简化了您的查询并将子查询更改为左连接。

试一试,引擎应该更容易优化,如果不是,您也更容易优化。

在优化之前确保您的统计数据是最新的。

SELECT
            [C].[County],
            [S].[State],
            [C].[County_ID]
    FROM
            [dbo].[Leads] [L] 
        JOIN
            [dbo].[Inventory] [I]
                ON [I].[Inv_ID] = [L].[Inv_ID]
        JOIN
            [dbo].[County] [C]
                ON [C].[County_ID] = [I].[County_ID]
        JOIN
            [dbo].[State] [S]
                ON [S].[State_ID] = [C].[State_ID]
        JOIN
            [dbo].[Contacts] [Co]
                ON [Co].[ID] = [L].[Contact_ID]
        LEFT JOIN
            [dbo].[Accounts] [A] (NOLOCK)
                ON [A].[Acct_ID] = [L].[Acct_ID]
    WHERE
            [L].[Deleted] = 0
        AND
            [S].[Active] = 1
        AND
            [Co].[Deleted] = 0
        AND
            (
                [L].[Acct_ID] = 204940
            OR
                [A].[Parent_Acct_ID] = 204940
            )
    GROUP BY
            [C].[County],
            [S].[State],
            [C].[County_ID]
    ORDER BY
            [S].[State],
            [C].[County]

考虑到 OP 自己的答案中的额外信息,可以进一步简化查询,

SELECT
            [C].[County],
            [S].[State],
            [C].[County_ID]
    FROM
            [dbo].[Leads] [L] 
        JOIN
            [dbo].[Inventory] [I]
                ON [I].[Inv_ID] = [L].[Inv_ID]
        JOIN
            [dbo].[County] [C]
                ON [C].[County_ID] = [I].[County_ID]
        JOIN
            [dbo].[State] [S]
                ON [S].[State_ID] = [C].[State_ID]
        JOIN
            [dbo].[Contacts] [Co]
                ON [Co].[ID] = [L].[Contact_ID]
        JOIN
            [dbo].[Accounts] [A] (NOLOCK)
                ON [A].[Acct_ID] = [L].[Acct_ID]
                    OR [A].[Parent_Acct_ID] = [L].[Acct_ID] 
    WHERE
            [L].[Deleted] = 0
        AND
            [S].[Active] = 1
        AND
            [Co].[Deleted] = 0
        AND
            [L].[Acct_ID] = 204940
    GROUP BY
            [C].[County],
            [S].[State],
            [C].[County_ID]
    ORDER BY
            [S].[State],
            [C].[County]

我对所有帮助我的人投了赞成票,但这最终成为了解决方案:

SELECT DISTINCT
    C.County
    , S.State
    , C.County_ID
FROM
    Leads L 
    INNER JOIN Contacts ON L.Contact_ID = Contacts.ID AND Contacts.Deleted = 0
    INNER JOIN Inventory I ON L.Deleted = 0 AND L.Inv_ID = I.Inv_ID
    INNER JOIN Accounts ON L.Acct_ID = Accounts.Acct_ID
        AND ( Accounts.Acct_ID = 204940 OR Accounts.parent_Acct_ID = 204940 )
    INNER JOIN County C ON C.County_ID = I.County_ID
    INNER JOIN State S ON C.State_ID = S.State_ID AND S.Active = 1
ORDER BY
    S.State
    , C.County

移动到 JOIN 而不是子 select 导致查询 运行 在 8 毫秒内而不是超过 30 秒。我知道在一个很好的级联中直接索引搜索而不是一堆向后过滤器和排序来找出谁属于查询。