Mam poniższe zapytanie:
select databasename
from somedb.dbo.bigtable l where databasename ='someval' and source <>'kt'
and not exists(select 1 from dbo.smalltable c where c.source=l.source)
Powyższe zapytanie kończy się w ciągu trzech sekund.
Jeśli powyższe zapytanie zwraca jakąkolwiek wartość, chcemy, aby procedura przechowywana zakończyła się, więc przepisałem ją jak poniżej:
If Exists(
select databasename
from somedb.dbo.bigtable l where databasename ='someval' and source <>'kt'
and not exists(select 1 from dbo.smalltable c where c.source=l.source)
)
Begin
Raiserror('Source missing',16,1)
Return
End
Jednak zajmuje to 10 minut.
Mogę przepisać powyższe zapytanie, jak poniżej, które również kończy się w mniej niż 3 sekundy:
select databasename
from somedb.dbo.bigtable l where databasename ='someval' and source <>'kt'
and not exists(select 1 from dbo.smalltable c where c.source=l.source
if @@rowcount >0
Begin
Raiserror('Source missing',16,1)
Return
End
Problem z powyższym przepisem polega na tym, że powyższe zapytanie jest częścią większej procedury składowanej i zwraca wiele zestawów wyników. W języku C # iterujemy każdy zestaw wyników i wykonujemy pewne przetwarzanie.
Powyższe zwraca pusty zestaw wyników, więc jeśli pójdę z tym podejściem, muszę zmienić mój C # i ponownie wdrożyć.
Więc moje pytanie brzmi:
dlaczego używanie tylko
IF EXISTS
zmienia plan, który zajmuje tak dużo czasu?
Poniżej znajdują się szczegółowe informacje, które mogą ci pomóc i dać mi znać, jeśli potrzebujesz jakichkolwiek szczegółów:
- Utwórz skrypt tabeli i statystyk, aby uzyskać taki sam plan jak mój
- Plan powolnej realizacji
Plan szybkiej realizacji
Powolny plan za pomocą Brentozar Wklej plan
Szybki plan za pomocą Brentozar Wklej plan
Uwaga: oba zapytania są takie same (przy użyciu parametrów), jedyna różnica polega na EXISTS
(mogłem popełnić błędy podczas anonimizacji).
Skrypty tworzenia tabel znajdują się poniżej:
http://pastebin.com/CgSHeqXc - statystyki małego stołu
http://pastebin.com/GUu9KfpS - statystyki dużego stołu