Je to jednoduchý výběr z dočasné tabulky, přičemž se vlevo připojí k existující tabulce na jejím primárním klíči, přičemž dva dílčí výběry používají první 1 odkazující na připojenou tabulku.
V kódu:
SELECT
TempTable.Col1,
TempTable.Col2,
TempTable.Col3,
JoinedTable.Col1,
JoinedTable.Col2,
(
SELECT TOP 1
ThirdTable.Col1 -- Which is ThirdTable's Primary Key
FROM
ThirdTable
WHERE
ThirdTable.SomeColumn = JoinedTable.SomeColumn
) as ThirdTableColumn1,
(
SELECT TOP 1
ThirdTable.Col1 -- Which is also ThirdTable's Primary Key
FROM
ThirdTable
WHERE
ThirdTable.SomeOtherColumn = JoinedTable.SomeColumn
) as ThirdTableColumn2,
FROM
#TempTable as TempTable
LEFT JOIN
JoinedTable
ON (TempTable.PKColumn1 = JoinedTable.PKColumn1 AND
TempTable.PKColumn2 = JoinedTable.PKColumn2)
WHERE
JoinedTable.WhereColumn IN (1, 3)
Toto je přesná replika mého dotazu.
Pokud odstraním dva dílčí výběry, bude to fungovat dobře a rychle. Díky těmto dvěma dílčím výběrům dostanu asi 100 záznamů za sekundu, což je pro tento dotaz extrémně pomalé, protože by se mělo vrátit téměř milion záznamů.
Zkontroloval jsem, jestli každý stůl má primární klíč, všichni ano. Všichni mají Indexy A statistiky pro své důležité sloupce, jako jsou ty v těchto klauzulích WHERE a ty v klauzuli JOIN. Jediná tabulka bez definovaného primárního klíče ani indexu je dočasná tabulka, ale není to problém ani proto, že se nejedná o tabulku týkající se pomalých dílčích výběrů, a jak jsem již zmínil, bez žádných dílčích výběrů to nefunguje dobře.
Bez nich TOP 1
vrátí více než jeden výsledek a vyvolá chybu.
Pomozte, někdo?
UPRAVIT :
Takže plán provádění mi řekl, že mi chybí index. Vytvořil jsem to a znovu vytvořil některé další indexy. Po chvíli je prováděcí plán používal a dotaz nyní běží rychle. Jediným problémem je, že se mi to nepodaří znovu provést na jiném serveru pro stejný dotaz. Takže mým řešením bude HINT, který index SQL Server použije.
Myslím, že v milionu záznamů dotazu, musíte se vyhnout věci jako OUTER JOINS
. Navrhuji použít UNION ALL
Namísto LEFT JOIN
. Dokud si myslím, že CROSS APPLY
Je ve výběrové klauzuli účinnější než dílčí dotaz, upravím dotaz napsaný Conardem Frixem, který je podle mě správný.
nyní: Když jsem začal upravovat váš dotaz, všiml jsem si, že máte klauzuli WHERE, která říká: JoinedTable.WhereColumn IN (1, 3)
. v tomto případě, pokud je pole neplatné, podmínka se stane chybnou. tak proč používáte LEFT JOIN, zatímco filtrujete řádky s nulovou hodnotou? stačí nahradit LEFT JOIN
Za INNER JOIN
zaručuji, že se zrychlí.
asi INDEX:
mějte na paměti, že když máte na stole index, řekněme
table1(a int, b nvarchar)
a váš index je:
nonclustered index ix1 on table1(a)
a chcete udělat něco takového:
select a,b from table1
where a < 10
do svého indexu jste nezahrnuli sloupec b
tak co se stane?
pokud sql-server používá váš index, bude muset hledat v indexu, nazvaný "Index Seek" a potom se podívat na hlavní tabulku, aby získal sloupec b
, nazvaný "Vyhledat". Tento postup může trvat mnohem déle než prohledávání samotné tabulky: "Testování tabulky".
ale na základě statistik, které má server sql, v takových situacích nemusí váš index vůbec používat.
nejprve proto zkontrolujte Execution Plan
, abyste zjistili, zda se index vůbec používá.
pokud ano nebo ne, změňte index tak, aby zahrnoval všechny sloupce, které vyberete. řekni jako:
nonclustered index ix1 on table1(a) include(b)
v takovém případě nebude vyhledávání nutné a váš dotaz bude spuštěn mnohem rychleji.
Je to dílčí výběr ve výběru sloupců, který způsobuje pomalý návrat. Měli byste zkusit použít dílčí výběry v levém spojení nebo použít odvozenou tabulku, jak jsem definoval níže.
Použití levého připojení ke dvěma instancím třetí tabulky
SELECT
TempTable.Col1,
TempTable.Col2,
TempTable.Col3,
JoinedTable.Col1,
JoinedTable.Col2,
ThirdTable.Col1 AS ThirdTableColumn1,
ThirdTable2.Col1 AS ThirdTableColumn2
FROM #TempTable as TempTable
LEFT JOIN JoinedTable ON (TempTable.PKColumn1 = JoinedTable.PKColumn2 AND
TempTable.PKColumn 2 = JoinedTable.PKColumn2)
LEFT JOIN ThirdTable ON ThirdTable.SomeColumn = JoinedTable.SomeColumn
LEFT JOIN ThirdTable ThirdTable2 ON ThirdTable.SomeOtherColumn = JoinedTable.SomeColumn
WHERE
JoinedTable.WhereColumn IN (1, 3)
Použití odvozené tabulky
SELECT
TempTable.Col1,
TempTable.Col2,
TempTable.Col3,
DerivedTable.Col1,
DerivedTable.Col2,
DerivedTable.ThirdTableColumn1,
DerivedTable.ThirdTableColumn2
FROM #TempTable as TempTable
LEFT JOIN (SELECT
JoinedTable.PKColumn2,
JoinedTable.Col1,
JoinedTable.Col2,
JoinedTable.WhereColumn,
ThirdTable.Col1 AS ThirdTableColumn1,
ThirdTable2.Col1 AS ThirdTableColumn2
FROM JoinedTable
LEFT JOIN ThirdTable ON ThirdTable.SomeColumn = JoinedTable.SomeColumn
LEFT JOIN ThirdTable ThirdTable2 ON ThirdTable.SomeOtherColumn = JoinedTable.SomeColumn)
DerivedTable ON (TempTable.PKColumn1 = DerivedTable .PKColumn2 AND
TempTable.PKColumn2 = DerivedTable.PKColumn2)
WHERE
DerivedTable.WhereColumn IN (1, 3)
Zkuste místo toho použít kříž
SELECT
TempTable.Col1,
TempTable.Col2,
TempTable.Col3,
JoinedTable.Col1,
JoinedTable.Col2,
ThirdTableColumn1.col1,
ThirdTableColumn2.col1
FROM
#TempTable as TempTable
LEFT JOIN
JoinedTable
ON (TempTable.PKColumn1 = JoinedTable.PKColumn2 AND
TempTable.PKColumn 2 = JoinedTablePKColumn2)
CROSS APPLY
(
SELECT TOP 1
ThirdTable.Col1 -- Which is ThirdTable's Primary Key
FROM
ThirdTable
WHERE
ThirdTable.SomeColumn = JoinedTable.SomeColumn
) as ThirdTableColumn1
CROSS APPLY (
SELECT TOP 1
ThirdTable.Col1 -- Which is also ThirdTable's Primary Key
FROM
ThirdTable
WHERE
ThirdTable.SomeOtherColumn = JoinedTable.SomeColumn
) as ThirdTableColumn2,
WHERE
JoinedTable.WhereColumn IN (1, 3)
Můžete také použít CTE a row_number nebo inline dotaz pomocí MIN
Přesuňte JOIN bity z hlavní části klauzule a vložte ji jako dílčí výběr. Přesunutí do sekce WHERE a JOIN zaručuje, že nemusíte znovu a znovu vybírat TOP 1, což je podle mě důvod ke zpomalení. Pokud to chcete zkontrolovat, zkontrolujte plán provádění.
Odkazy ThirdTable
(dílčí výběr v příkladu) vyžadují stejnou pozornost indexu jako kterákoli jiná část dotazu.
Bez ohledu na to, zda používáte dílčí výběr:
(
SELECT TOP 1
ThirdTable.Col1 -- Which is ThirdTable's Primary Key
FROM
ThirdTable
WHERE
ThirdTable.SomeColumn = JoinedTable.SomeColumn
) as ThirdTableColumn1,
(
SELECT TOP 1
ThirdTable.Col1 -- Which is also ThirdTable's Primary Key
FROM
ThirdTable
WHERE
ThirdTable.SomeOtherColumn = JoinedTable.SomeColumn
) as ThirdTableColumn2,
LEFT JOINS (jak navrhuje John Hartsock):
LEFT JOIN ThirdTable ON ThirdTable.SomeColumn = JoinedTable.SomeColumn
LEFT JOIN ThirdTable ThirdTable2 ON ThirdTable.SomeOtherColumn = JoinedTable.SomeColumn
CROSS APPLY (jak navrhuje Conrad Frix):
CROSS APPLY
(
SELECT TOP 1
ThirdTable.Col1 -- Which is ThirdTable's Primary Key
FROM
ThirdTable
WHERE
ThirdTable.SomeColumn = JoinedTable.SomeColumn
) as ThirdTableColumn1
CROSS APPLY (
SELECT TOP 1
ThirdTable.Col1 -- Which is also ThirdTable's Primary Key
FROM
ThirdTable
WHERE
ThirdTable.SomeOtherColumn = JoinedTable.SomeColumn
) as ThirdTableColumn2
Musíte zajistit covering indexes
jsou definovány pro ThirdTable.SomeColumn
a ThirdTable.SomeOtherColumn
a indexy jsou jedinečné. To znamená, že budete muset dále kvalifikovat odkazy ThirdTable
, abyste eliminovali výběr více řádků a zlepšili výkon. Volba sub selects
, LEFT JOIN
nebo CROSS APPLY
nebude opravdu záležet, dokud nezlepšíte selektivitu pro ThirdTable.SomeColumn
a ThirdTable.SomeOtherColumn
zahrnutím více sloupců pro zajištění jedinečné selektivity. Do té doby očekávám, že váš výkon bude i nadále trpět.
The covering index
téma je pěkně představil Maziar Taheri; I když jeho práci neopakuji, zdůrazňuji potřebu vzít v úvahu používání krycích indexů.
Zkrátka: Vylepšete selektivitu pro ThirdTable.SomeColumn
a ThirdTable.SomeOtherColumn
dotazy (nebo spojení) přidáním souvisejících sloupců v tabulce, aby byla zajištěna jedinečná shoda řádků. Pokud to není možné, budete i nadále trpět problémy s výkonem, protože motor je zaneprázdněn tažením v řádcích, které jsou následně vyhozeny. To má vliv na váš i/o, cpu a nakonec i plán provádění.