【问题标题】:Optimising CTE for recursive queries为递归查询优化 CTE
【发布时间】:2011-04-22 23:13:55
【问题描述】:

我有一张自联接的表。您可以将结构视为表示组织层次结构的标准表。例如表:-

MemberId
MemberName
RelatedMemberId

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

我怎样才能提高性能,因为 50000 并不是那么大的数字。随着时间的推移,它会不断增加。这正是我在存储过程中所拥有的查询。查询的目的是选择特定成员下的所有成员。例如。在公司所有者的领导下,每个人都来了。对于经理,除了所有者之外的所有记录都被返回。希望您了解查询的目的。

设置 ANSI_NULLS ON 去 设置 QUOTED_IDENTIFIER ON 去吧

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 的基本步骤和递归步骤中进行连接(而不是最后一步的 Select),则查询需要 20 分钟才能执行!

MemberId 是表中的主键。

提前致谢:)

【问题讨论】:

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


    【解决方案1】:

    在您的锚点条件下,您有Where IsNull(MemberId,0) = IsNull(@MemberId,0) 我认为这只是因为当您将NULL 作为参数传递时,= 在带回IS NULL 值方面不起作用。这将导致扫描而不是搜索。

    使用WHERE MemberId = @MemberId OR (@MemberId IS NULL AND MemberId IS NULL) 代替 sargable。

    另外我假设您不能在RelatedMemberId 上建立索引。如果没有,你应该添加一个

    CREATE NONCLUSTERED INDEX ix_name ON Members(RelatedMemberId) INCLUDE (MemberId)
    

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

    【讨论】: