Alguma idéia de por IF EXISTS
que isso faria com que ela durasse muito mais tempo e fizesse mais leituras? Também mudei a instrução select para fazer SELECT TOP 1 [dlc].[id]
e a matei após 2 minutos.
Como expliquei na minha resposta a esta pergunta relacionada:
Como (e por que) o TOP afeta um plano de execução?
Usando EXISTS
apresenta uma meta de linha, na qual o otimizador produz um plano de execução destinado a localizar a primeira linha rapidamente. Ao fazer isso, assume que os dados são distribuídos uniformemente. Por exemplo, se as estatísticas mostrarem 100 correspondências esperadas em 100.000 linhas, ele assumirá que precisará ler apenas 1.000 linhas para encontrar a primeira correspondência.
Isso resultará em tempos de execução mais longos do que o esperado, se essa suposição estiver com defeito. Por exemplo, se o SQL Server escolher um método de acesso (por exemplo, verificação não ordenada) que localizar o primeiro valor correspondente muito tarde na pesquisa, isso poderá resultar em uma verificação quase completa. Por outro lado, se uma linha correspondente for encontrada entre as primeiras, o desempenho será muito bom. Esse é o risco fundamental das metas de linha - desempenho inconsistente.
Como uma correção temporária, eu a alterei para fazer uma contagem (*) e atribuir esse valor a uma variável
Geralmente, é possível reformular a consulta para que uma meta de linha não seja atribuída. Sem o objetivo da linha, a consulta ainda pode terminar quando a primeira linha correspondente for encontrada (se gravada corretamente), mas a estratégia do plano de execução provavelmente será diferente (e, esperançosamente, mais eficaz). Obviamente, count (*) exigirá a leitura de todas as linhas, portanto, não é uma alternativa perfeita.
Se você estiver executando o SQL Server 2008 R2 ou posterior, geralmente também poderá usar o sinalizador de rastreamento documentado e suportado 4138 para obter um plano de execução sem uma meta de linha. Esse sinalizador também pode ser especificado usando a dica suportada OPTION (QUERYTRACEON 4138)
, embora esteja ciente de que requer permissão sysadmin de tempo de execução , a menos que seja usado com um guia de plano.
Infelizmente
Nenhuma das opções acima é funcional com uma IF EXISTS
declaração condicional. Aplica-se apenas ao DML regular. Ele vai trabalhar com o suplente SELECT TOP (1)
formulação você tentou. Isso pode ser melhor do que usarCOUNT(*)
, que precisa contar todas as linhas qualificadas, como mencionado anteriormente.
Dito isso, existem várias maneiras de expressar esse requisito que permitirão evitar ou controlar a meta da linha, ao encerrar a pesquisa antecipadamente. Um último exemplo:
DECLARE @Exists bit;
SELECT @Exists =
CASE
WHEN EXISTS
(
SELECT [dlc].[ID]
FROM TableDLC [dlc]
JOIN TableD [d]
ON [d].[ID] = [dlc].[ID]
JOIN TableC [c]
ON [c].[ID] = [d].[ID2]
WHERE [c].[Name] <> [dlc].[Name]
)
THEN CONVERT(bit, 1)
ELSE CONVERT(bit, 0)
END
OPTION (QUERYTRACEON 4138);
IF @Exists = 1
BEGIN
...
END;
IF NOT EXISTS (...) BEGIN END ELSE BEGIN <do something> END
.