Układanka optymalizatora zapytań SQL Server 2008 R2
Mamy dwie tabele, każda zawierająca 9 milionów wierszy. 70 000 wierszy jest różnych, pozostałe są takie same.
To jest szybkie, 13 sekund,
select * from bigtable1
except select * from similar_bigtable2
To sortuje dane wyjściowe i jest również szybkie, również 13 sekund,
select * into #q from bigtable1
except select * from similar_bigtable2
select * from #q order by sort_column
Chociaż jest to niezwykle powolne:
;with q as (
select * from bigtable1
except select * from similar_bigtable2
)
select * from q order by sort_column
Nawet „sztuczka”, której czasem używam, aby zasugerować programowi SQL Server, że musi wstępnie obliczyć określoną część zapytania, zanim przejdzie dalej, nie działa i powoduje również wolne zapytanie:
;with q as (
select top 100 percent * from bigtable1
except select * from similar_bigtable2
)
select * from q order by sort_column
Patrząc na plany zapytań, nie jest trudno znaleźć przyczynę:
SQL Server umieszcza dwa rodzaje 9 milionów wierszy przed hashatchem, podczas gdy wolałbym, aby dodał tylko jeden rodzaj 70 000 wierszy po hashatchu.
Więc pytanie: jak mogę polecić optymalizatorowi zapytań, aby to zrobił?
EXCEPT
(np. OUTER JOIN
)? Zdaję sobie sprawę, że składnia jest mniej wygodna, ale możesz lepiej grać ze wskazówkami dotyczącymi indeksowania / dołączania (lub nie musisz). Alternatywą, której teraz używasz (najpierw wstawianie do tabeli temperatur) jest obejście w ostateczności, ale w niektórych przypadkach jest to jedyny sposób, aby zmusić optymalizator do całkowitego oddzielenia dwóch części zapytania w pożądany sposób.