Query di SQL Server lenta quando impaginata


14

Sto riscontrando un comportamento strano con la seguente query T-SQL in SQL Server 2012:

SELECT Id 
FROM dbo.Person 
WHERE CONTAINS(Name, '"John" AND "Smith"')
ORDER BY Name

L'esecuzione di questa query da sola mi dà circa 1.300 risultati in meno di due secondi (c'è un indice full-text attivo Name)

Tuttavia, quando cambio la query in questo:

SELECT Id 
FROM dbo.Person 
WHERE CONTAINS(Name, '"John" AND "Smith"')
ORDER BY Name
OFFSET 0 rows
FETCH NEXT 10 ROWS ONLY

Ci vogliono più di 20 secondi per darmi 10 risultati.

La seguente query è ancora peggiore:

SELECT Id 
FROM ( 
    SELECT ROW_NUMBER() OVER (ORDER BY Name) AS RowNum, Id 
    FROM dbo.Person
    WHERE CONTAINS(Name, '"John" AND "Smith"') ) AS RowConstrainedResult 
WHERE RowNum >= 0 AND RowNum < 11 
ORDER BY RowNum

Il completamento richiede più di 1,5 minuti!

Qualche idea?

Piano lento

Lento

Piano veloce

Veloce


Cosa succede se si modifica la seconda query in SELECT TOP 10 * .... ORDER BY Name?
Lamak

Su quali colonne viene creato l'indice IX_PersonSearch ...? Stai ottenendo una ricerca chiave perché stai selezionando * dalla tabella e l'indice utilizzato non contiene tutte le colonne di output. Penso che dovresti selezionare solo le colonne necessarie e quindi includerle nell'indice non cluster come colonne incluse, non colonne indice.
Marcel N.

Puoi pubblicare gli indici sul tavolo (creare uno script)?

3
L'ID è sempre incluso in ogni indice non cluster. Questo è il modo in cui SQL Server è in grado di eseguire ricerche chiave (per ID).
usr

1
Quello che ho dimenticato di menzionare: quando faccio la stessa query con LIKE invece che CONTAINS, è anche veloce. (Impaginato o no)

Risposte:


7

Dato che vuoi semplicemente TOP 10ordinare per nome, pensa che sarà più veloce lavorare sull'indice namein ordine e cercare di vedere se ogni riga corrisponde al CONTAINS(Name, '"John" AND "Smith"') )predicato.

Presumibilmente ci vogliono molte più righe per trovare le 10 corrispondenze richieste, quindi si aspetta e questo problema di cardinalità è aggravato dal numero di ricerche chiave.

Un hack veloce per fermarlo usando questo piano sarebbe quello di cambiare il ORDER BYverso ORDER BY Name + '', anche se utilizzando CONTAINSTABLEin combinazione con FORCE ORDERdovrebbe anche lavoro.


3

Sembra una classica stima della selettività. Non sono sicuro di cosa si possa fare al riguardo come "driver" della query è la ricerca full text che non è possibile aumentare con le statistiche.

Prova a riscrivere il where containspredicato in un inner join containstable( CONTAINSTABLE ) e applica i suggerimenti dell'ordine dei join per forzare la forma del piano.

Questa non è una soluzione perfetta perché ha problemi di manutenzione, ma non riesco a vedere un altro modo.


Grazie per la tua risposta, l'ho provato. Stesso risultato però: quando non si utilizza l'impaginazione, la query è molto veloce. Quando impagina improvvisamente diventa di nuovo molto lento: /

Ok, puoi pubblicare il piano come immagine e la tua richiesta? Suppongo che non siamo ancora riusciti a generare la forma desiderata.
usr

3

Sono riuscito a risolvere il problema:

Come ho detto nella domanda, c'erano tutti gli indici su tutte le colonne + statistiche per ogni colonna. (A causa delle query LIKE legacy) ho rimosso tutti gli indici e le statistiche, aggiunto la ricerca full-text e voilà, la query è diventata molto veloce.

Sembra che le indicazioni abbiano condotto a un diverso piano di esecuzione.

Grazie mille a tutti per il vostro aiuto!


1
Bene, cancellare completamente l'indice è un modo per impedirne l'uso!
Martin Smith,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.