IN谓词上的表扫描和急切线轴

时间:2015-03-09 12:59:47

标签: sql sql-server tsql

我正在运行我认为是一个相当简单的查询,并且我在查询中获得了非常糟糕的返回时间。运行查询时,作为IN谓词中的过滤器的子查询在用作查询的一部分时执行索引扫描和索引假脱机,但在{{1}之外使用时运行索引查找谓词。我不明白为什么,但查询花了将近30秒才能返回零记录...

以下是查询:

IN

这是该查询的执行计划的相关部分。它在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 子句中的Accounts表上运行扫描,估计返回的行数超过260,000。子选择实际上返回0条记录。

enter image description here

当我在上面的查询之外运行那个简单的选择时,我得到一个直接的索引搜索,与完全相同的索引。子选择返回0条记录。如果我在没有WHERE语句的情况下运行查询,则会得到ms响应时间,如果我使用OR语句运行查询,则查询需要将近30秒才能完成。

这里是用于“帐户”表上“扫描”和“搜索”的索引(我知道,它是一个dta索引,而不是我原来的数据库......)

OR

如何让subselect运行Index Seek而不是Scan,并在任何合理的时间内返回?

3 个答案:

答案 0 :(得分:1)

试试这个:

   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

答案 1 :(得分:1)

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

试一试,引擎应该更容易优化,如果没有,更容易优化。

在优化之前,请确保您的统计信息是最新的。

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]

答案 2 :(得分:0)

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

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而不是子选择导致查询在8ms而不是30秒内运行。我知道有一个很好的级联直接索引寻找而不是一堆反向过滤器和排序来确定谁属于查询。