it-swarm.it

SQL Select impiega troppo tempo per essere eseguito

È una selezione semplice da una tabella temporanea, a sinistra che unisce una tabella esistente sulla sua chiave primaria, con due sotto-selezioni che usano la prima 1 che fa riferimento alla tabella unita.

Nel codice:

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)

Questa è una replica esatta della mia domanda.

Se rimuovo i due sottoselezioni, funziona perfettamente e rapidamente. Con i due sottoselezioni, ottengo circa 100 record al secondo, il che è estremamente lento per questa query perché dovrebbe restituire quasi un milione di record.

Ho controllato per vedere se ogni tabella ha una chiave primaria, lo fanno tutti. Tutti hanno indici e statistiche per le loro colonne importanti, come quelli nelle clausole WHERE e quelli nella clausola JOIN. L'unica tabella senza chiave primaria definita né indice è la tabella temporanea, ma non è nemmeno il problema perché non è quella relativa alle selezioni secondarie lente e, come ho già detto, senza le selezioni secondarie funziona alla perfezione.

Senza quelli TOP 1 restituisce più di un risultato e genera un errore.

Aiuto qualcuno?

[~ ~ #] modifica [~ ~ #]:

Quindi il piano di esecuzione mi ha detto che mi mancava un indice. L'ho creato e ricreato alcuni degli altri indici. Dopo un po ', il piano di esecuzione li utilizzava e la query ora viene eseguita rapidamente. L'unico problema è che non riesco a farlo di nuovo su un altro server, per la stessa query. Quindi la mia soluzione sarà quella di SUGGERIMENTO quale indice verrà utilizzato da SQL Server.

9
Smur

Penso che in una query su un milione di record, devi evitare cose come OUTER JOINS. Ti suggerisco di usare UNION ALL Invece di LEFT JOIN. Finché ritengo che CROSS APPLY Sia più efficiente della sottoquery nella clausola select, modificherò la query scritta da Conard Frix, che ritengo corretta.

ora: quando ho iniziato a modificare la tua query ho notato che hai una clausola WHERE che dice: JoinedTable.WhereColumn IN (1, 3). in questo caso, se il campo è null la condizione diventerà falsa. allora perché stai usando LEFT JOIN mentre stai filtrando le righe con valore nullo? sostituisci LEFT JOIN Con INNER JOIN, ti garantisco che diventerà più veloce.

su INDICE:

si prega di notare che quando si dispone di un indice su una tabella, ad esempio

table1(a int, b nvarchar)

e il tuo indice è:

nonclustered index ix1 on table1(a)

e vuoi fare qualcosa del genere:

select a,b from table1
where a < 10

nel tuo indice non hai incluso la colonna b quindi cosa succede?

se sql-server usa il tuo indice, dovrà cercare nell'indice, chiamato "Index Seek" e quindi fare riferimento alla tabella principale per ottenere la colonna b, chiamata "Cerca". Questa procedura potrebbe richiedere molto più tempo rispetto alla scansione della tabella stessa: "Scansione tabella".

ma in base alle statistiche fornite da sql-server, in tali situazioni, potrebbe non utilizzare affatto il tuo indice.

quindi prima di tutto controlla Execution Plan per vedere se l'indice è usato affatto.

se sì o no entrambi, modifica il tuo indice per includere tutte le colonne che stai selezionando. dire come:

nonclustered index ix1 on table1(a) include(b)

in questo caso non sarà necessario cercare e la query verrà eseguita molto più velocemente.

7
Maziar Taheri

È il sottoseleziona nella selezione della colonna che sta causando il ritorno lento. Dovresti provare a usare i tuoi sub-seletti nei join di sinistra o utilizzare una tabella derivata come ho definito di seguito.

so dei join di sinistra in due istanze della terza tabella

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)

tilizzo di una tabella derivata

 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

Prova invece una croce

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)

Puoi anche usare CTE e row_number o una query inline usando MIN

2
Conrad Frix

Spostare i bit JOIN fuori dalla parte principale della clausola e metterlo come sottoselezione. Spostarlo nella sezione WHERE e JOIN garantisce che non devi SELEZIONARE ripetutamente TOP 1, che credo sia la ragione della sua lentezza. Se si desidera verificare ciò, esaminare il piano di esecuzione.

2
Gregory A Beamer

I riferimenti ThirdTable, (seleziona i sub nel tuo esempio), richiedono la stessa attenzione all'indice di qualsiasi altra parte di una query.

Indipendentemente dal fatto che si utilizzi i sottoseleziona:

(
    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,

JOIN SINISTRA (come proposto da John Hartsock):

LEFT JOIN ThirdTable ON ThirdTable.SomeColumn = JoinedTable.SomeColumn
LEFT JOIN ThirdTable ThirdTable2 ON ThirdTable.SomeOtherColumn = JoinedTable.SomeColumn

CROSS APPLY (come proposto da 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

Devi assicurarti covering indexes sono definiti per ThirdTable.SomeColumn e ThirdTable.SomeOtherColumn e gli indici sono unici. Ciò significa che dovrai qualificare ulteriormente i riferimenti ThirdTable per eliminare la selezione di più righe e migliorare le prestazioni. La scelta di sub selects, LEFT JOIN, o CROSS APPLY non importerà fino a quando non migliorerai la selettività per ThirdTable.SomeColumn e ThirdTable.SomeOtherColumn includendo più colonne per garantire una selettività unica. Fino ad allora, mi aspetto che la tua performance continuerà a soffrire.

Il covering index L'argomento è ben presentato da Maziar Taheri; pur non ripetendo il suo lavoro, sottolineo la necessità di prendere a cuore l'uso degli indici di copertura.

In breve: migliora la selettività per il ThirdTable.SomeColumn e ThirdTable.SomeOtherColumn query (o join) aggiungendo colonne correlate nella tabella per garantire una corrispondenza di riga univoca. Se ciò non è possibile, continuerai a soffrire di problemi di prestazioni poiché il motore è impegnato a tirare in file che vengono successivamente gettate via. Ciò influisce sul tuo I/O, CPU e, in definitiva, sul piano di esecuzione.

2
Robert Miller