Domanda

E 'una semplice selezionare da una tabella temporanea, sinistra unendo una tabella esistente sulla sua chiave primaria, con due sub seleziona usando la parte superiore 1 del rinvio 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 interrogazione.

Se rimuovo i due seleziona sub, funziona bene e rapidamente. Con i due seleziona sub, ricevo circa 100 record al secondo, il che è estremamente lento per questa query perché deve restituire quasi un milione di dischi.

Ho controllato per vedere se ogni tavolo ha una chiave primaria, fanno tutti. Sono tutte dotate di indici e statistiche per le loro colonne importanti, come quelle in quelli in cui clausole, e quelli nel join clausola. L'unico tavolo con nessuna chiave primaria definita né indice è la tabella temporanea, ma non è il problema sia perché non è quello relativo alle seleziona sub lento, e come ho detto, con non ha nessun problema seleziona funziona bene.

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

Guida, chiunque?

Modifica :

Quindi, il piano di esecuzione mi ha detto che mi mancava un Indice. Ho creato, e ricreato alcuni degli altri indici. Dopo un po ', il piano di esecuzione li stava usando, e la query ora corre veloce. L'unico problema è che non sto riuscendo a fare di nuovo su un altro server, per la stessa query. Così la mia soluzione sarà quella di SUGGERIMENTO quale indice di SQL Server utilizzerà.

È stato utile?

Soluzione

Credo che in una query milione di record, si deve evitare cose come OUTER JOINS. Vi suggerisco di utilizzare UNION ALL Invece di LEFT JOIN. Finché penso CROSS APPLY è più efficiente di sub-query nella clausola select farò modificare la query scritta da Conard Frix, che credo sia corretto.

ora: quando ho iniziato a modificare la query ho notato che hai una clausola WHERE dicendo: JoinedTable.WhereColumn IN (1, 3). in questo caso, se il campo è null la condizione diventerà falsa. allora perché stai usando LEFT JOIN mentre si sta filtrando nulli righe valutati? basta sostituire LEFT JOIN Con INNER JOIN, vi garantisco che diventerà più veloce.

su INDEX:

Si noti che quando si dispone di un indice in una tabella, ad esempio

table1(a int, b nvarchar)

e l'indice è:

nonclustered index ix1 on table1(a)

e si vuole fare qualcosa di simile:

select a,b from table1
where a < 10

nell'indice non avete incluso la b colonna in modo che cosa succede?

Se SQL-server utilizza l'indice, si dovrà cercare nell'indice, denominata "Index Seek" e quindi fare riferimento alla tabella principale per ottenere colonna b, chiamato "Look Up ". Questa procedura potrebbe richiedere molto più tempo di scansione della tabella stessa:. "Tabella di scansione"

, ma in base alle statistiche che SQL-server è, in tali situazioni, potrebbe non utilizzare l'indice a tutti.

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

se sì o no entrambi, alterare l'indice per includere tutte le colonne che si sta selezionando. dire come:

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

in questo caso non sarà necessario Look Up, e la query verrà eseguita in modo molto più veloce.

Altri suggerimenti

I suoi i sub seleziona nella selezione colonna che sta causando il lento ritorno. Si dovrebbe provare a utilizzare i vostri sub-select a sinistra join, o utilizzare una tabella derivata come ho definito di seguito.

Utilizzo di sinistra si unisce a due istanze di Terza tavola

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)

Utilizzo di una derivate tavola

 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)

Prova a croce si applicano invece

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)

È inoltre possibile utilizzare CTE e row_number o una query in linea con MIN

Spostare il JOIN bit dalla parte principale della clausola e metterlo come una selezione secondaria. Spostandolo a WHERE e PARTE DELLA SEZIONE garanzie che non è necessario selezionare TOP 1 più e più volte, che credo è la ragione per HTE lentezza. Se si desidera controllare questo, esaminare il piano di esecuzione.

I riferimenti ThirdTable, (sub Seleziona nel tuo esempio), hanno bisogno la stessa attenzione indice come qualsiasi altra parte di una query.

Non importa se si utilizza sub seleziona:

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

A SINISTRA SI UNISCE (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

È necessario garantire covering indexes sono definiti per ThirdTable.SomeColumn e ThirdTable.SomeOtherColumn e gli indici sono unici. Questo significa che sarà necessario 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 sarà davvero importa fino a migliorare la selettività per ThirdTable.SomeColumn e ThirdTable.SomeOtherColumn includendo più colonne al fine di garantire la selettività unica. Fino ad allora, mi aspetto le vostre prestazioni continuerà a soffrire.

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

In breve: Migliorare la selettività per i ThirdTable.SomeColumn e ThirdTable.SomeOtherColumn query (o join) aggiungendo legati colonne tabella per assicurare una corrispondenza riga univoco. Se questo non è possibile, allora si continuerà a soffrire problemi di prestazioni come il motore è occupato tirando in righe che vengono successivamente gettati via. Ciò influisce il vostro I / O, CPU, e, in ultima analisi, il piano di esecuzione.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a dba.stackexchange
scroll top