it-swarm-eu.dev

Výběr SQL trvá příliš dlouho na provedení

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.

9
Smur

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.

7
Maziar Taheri

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)
6
John Hartsock

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

2
Conrad Frix

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í.

2
Gregory A Beamer

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í.

2
Robert Miller