Qualche idea sul perché lo IF EXISTS
farebbe funzionare così a lungo e fare così tante altre letture? Ho anche cambiato l'istruzione select da fare SELECT TOP 1 [dlc].[id]
e l'ho uccisa dopo 2 minuti.
Come ho spiegato nella mia risposta a questa domanda correlata:
In che modo (e perché) TOP influisce su un piano di esecuzione?
L'utilizzo EXISTS
introduce un obiettivo di riga, in cui l'ottimizzatore produce un piano di esecuzione volto a individuare rapidamente la prima riga. Nel fare ciò, si presuppone che i dati siano distribuiti uniformemente. Ad esempio, se le statistiche mostrano che ci sono 100 partite attese in 100.000 righe, supporrà che dovrà leggere solo 1.000 righe per trovare la prima partita.
Ciò comporterà tempi di esecuzione più lunghi del previsto se questo presupposto risulta essere difettoso. Ad esempio, se SQL Server sceglie un metodo di accesso (ad es. Scansione non ordinata) per individuare il primo valore corrispondente molto tardi nella ricerca, potrebbe risultare in una scansione quasi completa. D'altra parte, se tra le prime righe si trova una riga corrispondente, le prestazioni saranno molto buone. Questo è il rischio fondamentale con obiettivi di fila: prestazioni incoerenti.
Come soluzione temporanea l'ho modificato per fare un conteggio (*) e assegnare quel valore a una variabile
In genere è possibile riformulare la query in modo che non venga assegnato un obiettivo di riga. Senza l'obiettivo di riga, la query può comunque terminare quando viene rilevata la prima riga corrispondente (se scritta correttamente), ma è probabile che la strategia del piano di esecuzione sia diversa (e si spera, più efficace). Ovviamente, count (*) richiederà la lettura di tutte le righe, quindi non è un'alternativa perfetta.
Se si esegue SQL Server 2008 R2 o versioni successive, in genere è anche possibile utilizzare il flag di traccia 4138 documentato e supportato per ottenere un piano di esecuzione senza un obiettivo di riga. Questo flag può anche essere specificato utilizzando l' hint supportato OPTION (QUERYTRACEON 4138)
, sebbene si tenga presente che richiede l' autorizzazione sysadmin di runtime , a meno che non venga utilizzato con una guida di piano.
Sfortunatamente
Nessuna delle precedenti è funzionale con un'istruzione IF EXISTS
condizionale. Si applica solo al normale DML. Esso sarà lavorare con il alternativo SELECT TOP (1)
formulazione si è tentato. Potrebbe essere meglio dell'uso COUNT(*)
, che deve contare tutte le righe qualificate, come menzionato in precedenza.
Detto questo, ci sono molti modi per esprimere questo requisito che ti consentiranno di evitare o controllare l'obiettivo della riga, terminando la ricerca in anticipo. Un ultimo esempio:
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
.