优化CTE以进行递归查询

时间:2011-04-22 14:43:27

标签: sql sql-server-2005 sql-server-2008

我有一张自我加入的桌子。您可以将结构视为标准表来表示组织层次结构。例如表: -

MemberId
MemberName
RelatedMemberId

此表包含50000个样本记录。我写了CTE递归查询,它的工作非常好。然而,在我的机器上处理仅50000条记录所需的时间约为3分钟(4GB Ram,2.4 Ghz Core2Duo,7200 RPM HDD)。

我怎样才能提高性能,因为50000并不是那么庞大。随着时间的推移,它将继续增加。这是我的存储过程中的查询。查询的目的是选择属于特定成员的所有成员。例如。在公司的所有者之下,每个人都来了。对于Manager,除了所有者返回所有记录。我希望你理解查询的目的。

SET ANSI_NULLS ON 走 SET QUOTED_IDENTIFIER ON GO

Alter PROCEDURE spGetNonVirtualizedData
(
    @MemberId    int
)
AS
BEGIN

    With MembersCTE As
    (
        Select parent.MemberId As MemberId, 0 as Level
            From Members as parent Where IsNull(MemberId,0) = IsNull(@MemberId,0)

                    Union ALL
        Select    child.MemberId As MemberId , Level + 1 as Level
            From Members  as child
                Inner Join MembersCTE on MembersCTE.MemberId = child.RelatedMemberId
    )   
    Select Members.*
        From MembersCTE
        Inner Join Members On MembersCTE.MemberId = Members.MemberId
        option(maxrecursion 0)

END
GO

正如您所看到的那样,为了提高性能,我甚至在选择记录时最后一步创建了连接,以便不会将所有不必要的记录插入到临时表中。如果我在基本步骤和CTE的递归步骤中进行连接(而不是在最后一步中选择),则查询需要20分钟才能执行!

MemberId是表中的主键。

提前致谢:)

1 个答案:

答案 0 :(得分:9)

在您的锚定状态下,您有Where IsNull(MemberId,0) = IsNull(@MemberId,0)我认为这只是因为当您将NULL作为参数=传递时,IS NULL无法恢复WHERE MemberId = @MemberId OR (@MemberId IS NULL AND MemberId IS NULL)值。这将导致扫描而不是搜索。

使用RelatedMemberId代替 sargable。

另外我假设你不能在CREATE NONCLUSTERED INDEX ix_name ON Members(RelatedMemberId) INCLUDE (MemberId) 上有索引。如果没有,你应该添加一个

MemberId

(尽管如果{{1}}是聚集索引键,您可以跳过包含的列位,因为它将自动包含在内)