Eu tenho duas tabelas no Sql Server 2008 que se parecem com isto:
Transaction_Details:
Dataset,
Department,
Charge_ID,
Transaction_Type,
dos_month,
post_month,
amount
Charge_Summary
Dataset,
Department,
Charge_ID,
dos_month,
Ins1_Category
A saída que estou procurando seria mais ou menos assim: Dataset, Department, Ins1_Category, dos_month, Post_Month, Total_Payments, Total_Charges, Previous_Balance -- Definido como valor total para todas as transações correspondentes com um post_month anterior ao mês atual
O SQL que estou usando abaixo fornece a saída esperada, mas há uma busca de índice no plano de execução que ocupa mais de 90% do custo. Isso está em uma operação de datawarehouse, portanto, não há nenhuma outra atividade no servidor além dessa consulta, nenhuma outra leitura ou gravação com que se preocupar. O tempo de execução de aproximadamente 30 minutos é aceitável para o que está sendo usado, mas ainda gostaria de alguns conselhos se houver uma maneira melhor de fazer isso.
SELECT
t1.Dataset,
t1.Department,
c1.Ins1_Category,
t1.dos_month,
t1.post_month,
SUM(case
when t1.transaction_type = 'payment' THEN t1.amount
ELSE 0
END
) AS total_payments,
SUM(case
when t1.transaction_type = 'adjustment' THEN t1.amount
ELSE 0
END
) AS total_adjustments,
SUM(case
when t1.transaction_type = 'charge' THEN t1.amount
ELSE 0
END
) AS total_charges,
(
SELECT
SUM(t2.amount)
FROM
Transaction_Details t2
LEFT JOIN
Charge_Summary c2
ON
t2.Dataset = c2.Dataset AND
t2.Charge_ID = c2.Charge_ID
WHERE
t1.Dataset = t2.Dataset AND
t1.Department = t2.Department AND
t1.dos_month = t2.dos_month AND
t1.post_month > t2.post_month AND
t2.Charge_ID IS NOT NULL AND
c2.Ins1_Category = c1.Ins1_Category
) as previous_balance
FROM
Transaction_Details t1
LEFT JOIN
Charge_Summary c1
ON
t1.Dataset = c1.Dataset AND
t1.Charge_ID = c1.Charge_ID
WHERE
t1.Charge_ID is not null
GROUP BY
t1.Dataset,
t1.Department,
c1.Ins1_Category,
t1.dos_month,
t1.post_month
Além das técnicas de T-SQL discutidas no artigo de Aaron Bertrands, "Melhores abordagens para totais de execução agrupados" , talvez você queira examinar um
SQLCLR
procedimento (se estiver executando menos do que o SQL Server 2012).As principais vantagens são que um
SQLCLR
procedimento requer apenas uma única varredura dos registros de origem e se beneficia do aumento da velocidade de execução do código compilado. A amostra abaixo foi retirada da postagem de Aaron:DDL
Dados de amostra
Procedimento SQL CLR DDL
Uso
Resultado
Plano de execução
Código-fonte do SQL CLR
Eu nem preciso ver o plano de execução neste.
A subconsulta correlacionada que você usa para calcular o total em execução causará uma "autojunção triangular", para cada linha, você obtém todos os predecessores de sua tabela de fatos e, portanto, uma contagem de linhas impressionante (pense nas linhas de n²).
Se você quiser ajustar essa consulta, precisará reescrever o total acumulado de maneira mais eficiente. No SQL 2012 isso seria muito fácil, mas em 2008 você precisa ser um pouco mais criativo.
No topo da minha cabeça, 2 opções seriam pré-agregar agrupadas por mês como uma primeira etapa e, em uma tabela temporária, atualizar o total em execução de forma iterativa ou usando um CTE recursivo. É um problema bastante comum, então 5 minutos no Google devem encontrar toneladas de postagens de blog com muito mais detalhes do que eu posso aqui.