流式SQL Server 2008递归CTE

时间:2012-01-19 16:05:49

标签: sql-server-2008 recursion common-table-expression

我有一组表格(TableA)中的数据,这些数据通过TableB与自身相关联。 TableA中的父母有TableA的孩子。那些孩子也可能有孩子。这里没什么了不起的。

我有一个来自TableA的顶级行,我需要操作。在我可以对这些行进行操作之前,我必须手头有每个子行。我必须能够在我的应用程序中尽快对TableA(和它的孩子)的每个顶级行进行操作。

我找不到办法做到这一点。

使用递归CTE(TableA顶级集作为锚,TableB->TableA作为联合加入),不符合要求。来自TableA的整个顶级集在CTE中返回,然后在子级别2上工作。然后它在3级工作。然后是4级等。由于我的顶级设置是大约400,000多行,我的客户端应用程序无法开始处理行,直到ENTIRE数据集已经在服务器上批处理。

我需要一个更好的方法来做到这一点。我尝试将一组平顶级TableA行流式传输到客户端,并让客户端为每个顶级TableA行重复发出递归CTE语句。这实际上有效。但是噪音太大了。由于重复重新发布语句,持续的行检索率太大。

我需要一个有创意的解决方案。

我正在使用的每记录CTE的片段。在此示例中,TableA是Member,TableB是MemberReplacement。我在中间和大部分连接中删除了大部分select语句。

WITH T_MemberRecurse
(
    MemberId,
    IncludedMemberId,
    Level
) AS (
    SELECT      Member.Id,
                Member.Id,
                0
    FROM        MemberInput
    INNER JOIN  MemberInputItem
        ON      MemberInputItem.MemberInputId = MemberInput.Id
    INNER JOIN  Member
        ON      Member.Id = MemberInputItem.MemberId
    UNION ALL
    SELECT      T_MemberRecurse.MemberId,
                Member2.Id,
                Level + 1
    FROM        T_MemberRecurse
    INNER JOIN  Member
        ON      Member.Id = T_MemberRecurse.IncludedMemberId
    INNER JOIN  MemberReplacement
        ON      MemberReplacement.MemberId = Member.Id
    INNER JOIN  Member Member2
        ON      Member2.Id = MemberReplacement.OriginalMemberId
)
SELECT      Member.Id,
            T_MemberRecurse.IncludedMemberId,
            T_MemberRecurse.Level,

FROM        MemberInput
INNER JOIN  LotsOfTables

1 个答案:

答案 0 :(得分:1)

我现在正在考虑这个问题,但是由于我在链接服务器上遇到的经验导致逐行操作将性能提高了2个数量级,因此首先在黑暗中可能有所帮助。

将您的CTE转换为具有一个参数的行集返回函数,即所需的成员ID。

然后:

SELECT
   *
FROM
   Member M
   CROSS APPLY dbo.MemberChildren(M.Id) C
WHERE
   {Conditions for desired set of Members here}
WITH (FAST 20);

如果有效,请告诉我。我们的想法是强制引擎以深度优先而不是宽优先的方式进行遍历。它可能会降低整体服务器性能,但理论上应该让您的客户端开始使用某些数据行。

<强>更新

第二个想法:分别获取父和子信息,并在逻辑上执行客户端中的合并连接。 (有序嵌套循环,仅推进有序的第二个/内部输入,直到它不匹配。)使用键范围或row_number一次获取较小的块。或者获取整个父集,然后获得较小的子行集。

更新2

创意3:使用5个普通的vanilla连接来获取所需的所有数据,而不是递归CTE。这听起来很糟糕,但是应该让你快速完成数据。