给定一个自引用表
Item ------------- Id (pk) ParentId (fk)
与相关值的相关表
ItemValue ------------- ItemId (fk) Amount
还有一些样本数据
Item ItemValues Id ParentId ItemId Amount -------------------- ---------------------- 1 null 1 10 2 1 3 40 3 1 3 20 4 2 4 10 5 2 5 30 6 null 7 6 8 7
我需要一个存储程序来接送Item.Id直属孩子,并ItemValue.Amounts为他们,他们的孩子和他们的孩子一路走来。
Item.Id
ItemValue.Amounts
例如,如果1传入,则树将是2, 3, 4, 5直接子代2, 3,输出将是
1
2, 3, 4, 5
2, 3
ItemId Amount ------------------ 2 40 (values from ItemIds 4 & 5) 3 60 (values from ItemId 3)
应该采用哪种方法来实现此行为?
我正在考虑使用CTE,但想知道是否有更好/更快的方法。
假设您的层次结构不算太深,这样的递归CTE将可以工作:
declare @ParentId int; set @ParentId = 1; ;with Recurse as ( select a.Id as DirectChildId , a.Id from Item a where ParentId = @ParentId union all select b.DirectChildId , a.Id from Item a join Recurse b on b.Id = a.ParentId ) select a.DirectChildId, sum(b.Amount) as Amount from Recurse a left join ItemValues b on a.Id = b.ItemId group by DirectChildId;
非CTE方法将需要某种形式的迭代,基于游标或其他方式。由于它是存储的proc,因此有可能,并且如果要递归处理大量数据,则只要适当地对数据进行切片,它的伸缩性可能会更好。
如果聚集索引位于Id上,请在ParentId上添加非聚集索引。作为覆盖索引,它将满足不使用书签查找的初始搜索。然后,聚簇索引将有助于递归联接。
如果聚集索引已位于ParentId上,则在ID上添加非聚集索引。在一起,它们实际上将等同于上述内容。对于ItemValues,如果实际表的宽度大于此值,则可能需要在(ItemId)INCLUDE(Amount)上建立索引。