Qual correria mais rápido?
- Selecione em uma tabela usando a chave primária (inteiro, índice clusterizado, mais de 1.000.000 linhas)
- Tentar uma atualização em uma tabela diferente, onde a linha não existe? (cláusula where na chave primária inteira, índice clusterizado, mais de 200.000 linhas)
Fundo
Atualmente, temos alguns procedimentos que precisam manter uma cópia filtrada de sua tabela.
Mesas envolvidas:
[MasterTable]
que contém os critérios de filtro[ChildTable]
para ser filtrado[ChildFilterTable]
para manter os registros filtrados
Isso está sendo feito atualmente por:
- Selecionar critérios de filtro
- Se os critérios do filtro corresponderem, então:
- Tentar uma atualização
- Se nenhum registro atualizado, insira um novo registro
SQL de exemplo:
DECLARE @FilterValue INT
/* Get FilterValue to check */
SELECT @FilterValue = FilterValue FROM [MasterTable] WHERE ID = @IDFromChildTable
IF @FilterValue = 123
BEGIN
/* Attempt update */
UPDATE [ChildFilterTable] SET
...
WHERE ChildID = @IDFromChildTable
IF @@ROWCOUNT = 0
BEGIN
/* Row not there yet, insert it! */
INSERT INTO [ChildFilterTable] (ChildID, ....) VALUES (@IDFromChildTable, ....)
END
END
Alteração proposta
Mudar para:
- Tentar uma atualização
- Se nenhum registro for atualizado, então:
- Selecionar critérios de filtro
- Se os critérios do filtro corresponderem, então: insira um novo registro
Então:
DECLARE @FilterValue INT
/* Attempt update */
UPDATE [ChildFilterTable] SET
...
WHERE ChildID = @IDFromChildTable
IF @@ROWCOUNT = 0
BEGIN
/* Get FilterValue to check */
SELECT @FilterValue = FilterValue FROM [MasterTable] WHERE ID = @IDFromChildTable
IF @FilterValue = 123
BEGIN
/* Row not there yet, insert it! */
INSERT INTO [ChildFilterTable] (ChildID, ....) VALUES (@IDFromChildTable, ....)
END
END
Observação: as regras de negócios confirmam que o valor do filtro nunca será alterado após a configuração, [MasterTable]
portanto, não precisamos nos preocupar em atualizar um valor que não corresponda ao registro do filtro (ou seja: se estiver na ChildFilterTable, queremos atualizá-lo.
Você não pode usar a instrução MERGE adicionada com o SQL Server 2008 para "UPSERT" em uma operação atômica?
Você verificou o custo de seus INSERTs/UPDATEs?
Se você se preocupa com performance, eu sempre chamaria INSERT ou UPDATE primeiro, dependendo do que for mais provável de ser necessário em seu cenário. Portanto, se você espera que seus dados estejam em 80% dos casos já existentes, chame UPDATE primeiro e, em caso de falha, INSERT. Se o registro geralmente tiver que ser inserido na maioria dos casos, chame o INSERT primeiro.
O que você pode tentar é definir o tempo de estatísticas no início de ambas as consultas e revisar os resultados. Lembre-se de que, se a consulta estiver sendo armazenada em cache, você verá resultados diferentes; portanto, pode ser necessário limpar o cache durante o teste para ver como funcionam.