Tenho um data warehouse que passa por uma atualização completa todas as noites, o que pode levar cerca de uma hora para processar 16 milhões de linhas/25 gigas de dados e estamos procurando maneiras de reduzir esse tempo sem usar a abordagem incremental.
O formato básico de nossas consultas é o seguinte, apenas retirei cerca de 20 junções e mais de 30 colunas que também seriam incluídas. As colunas e junções removidas são muito diretas, sem agregação, subconsultas ou outros tipos de cálculo envolvidos. O que resta é a tabela de fatos principal (First_Source_Table) e o ponto de dados mais problemático a ser coletado. Second_Source_Table consiste em muitos registros para cada Account_ID, mas queremos incluir apenas o primeiro registro para cada Account_ID.
Agora minhas restrições. Isso em um ambiente replicado no SQL Server 2008. Infelizmente, não tenho controle sobre as tabelas de origem e, embora possa adicionar novos índices a elas, elas serão perdidas no dia seguinte. Eu tentei calcular uma tabela intermediária de Second_Source_Table antes de fazer a tabela completa, mas como isso precisaria ser recalculado a cada noite, isso não teve um impacto material no tempo de cálculo geral.
O código abaixo funciona, mas se você observar o plano de execução e IO Stats, a lógica associada a Second_Source_Table constitui cerca de 80% de todos os recursos usados, mas alterar esse campo para NULL apenas reduz o tempo de execução pela metade. Também vou apontar novamente que, sendo um ambiente replicado, não há problemas para se preocupar com o bloqueio ou outros usuários gravando nas tabelas em que estamos.
INSERT INTO
New_Table
SELECT
First_Source_Table.Account_ID,
(
select
top 1
Second_Source_Table.Code
FROM
Second_Source_Table
WHERE
Second_Source_Table.Account_ID = First_Source_Table.Account_ID
ORDER BY
Second_Source_Table.ID
) as Code
FROM
First_Source_Table
Você pode querer considerar o particionamento em vez de uma consulta escalar.
Então algo como