Qual é a melhor maneira de grupo e dados da árvore agregados e soma?
-
05-07-2019 - |
Pergunta
Dada uma tabela de auto referenciação
Item
-------------
Id (pk)
ParentId (fk)
Com uma tabela relacionada de valores associados
ItemValue
-------------
ItemId (fk)
Amount
E alguns dados de exemplo
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
Eu preciso de um sproc para tomar Item.Id
e retornar os filhos diretos com somas de todos ItemValue.Amounts
para eles, seus filhos e seus filhos todo o caminho até a árvore.
Por exemplo, se 1
é passado, a árvore seria 2, 3, 4, 5
os filhos diretos são 2, 3
a saída seria
ItemId Amount
------------------
2 40 (values from ItemIds 4 & 5)
3 60 (values from ItemId 3)
Que tipo de abordagens deve ser aplicado para fazer atingir esse comportamento?
Eu estou pensando em usar uma CTE, mas estou querendo saber se há uma melhor abordagem / mais rápido.
Solução
A recursiva CTE como isso iria funcionar, assumindo sua hierarquia não ir muito fundo:
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;
Um método não-CTE exigiria algum tipo de iteração,-cursor com base ou de outra forma. Desde que é um proc armazenados, é uma possibilidade, e se há um conjunto de dados muito a recurse através, ele provavelmente iria escalar melhor, contanto que você dividir os dados de forma adequada.
Se o índice de cluster está em Id, adicionar um índice não agrupado em ParentId. Como um índice de cobertura, que irá satisfazer a inicial procurar w / out uma pesquisa de indicador. O índice agrupado, então, ajuda com a recursiva participar.
Se o índice de cluster já está em ParentId em vez disso, adicionar um índice não agrupado em Id. Juntos, eles irão ser virtualmente equivalente ao anterior. Para ItemValues, você pode querer um índice em (ItemId) incluem (Valor), se a tabela real é maior do que isso.
Outras dicas
Será que isso tem que ser tratado no banco de dados? Gostaria de sugerir trazendo os dados necessários para a sua BLL e executar a recursão lá.