2009-08-18 18 views
8

Ho una tabella con circa 1 milione di record (con SQL Server 2008 Web in esecuzione). Ho una routine di ricerca che cerca di far corrispondere il codice del prodotto e la descrizione del prodotto. Tuttavia in alcune circostanze è molto lento. Qui di seguito è (cut-down) dichiarazione di sql:Perché questa istruzione SQL è molto lenta?

WITH AllProducts AS (
    SELECT  p.*, Row_Number() OVER (ORDER BY ProductId) AS RowNumber 
    FROM  Product AS p 
    WHERE p.IsEnabled=1 AND 
    (
     p.BaseSku = 'KPK-3020QWC-C' -- this on its own is fast 
     OR 
     CONTAINS(p.FreeTextStrings, '"KPK-3020QWC*"') -- and this on its own is fast, but not both 
    ) 
) SELECT * FROM AllProducts   
    WHERE RowNumber BETWEEN 1 AND 20; 

Nota che se ho appena confronto sulla [p.BaseSku = 'KPK-3020QWC-C'] o [contengono (p.FreeTextStrings, '"KPK-3020QWC * "')] individualmente (ma non entrambi) il suo istante. E se li paragono insieme ci vogliono anni (diversi minuti) - e restituisce solo una riga.

IsEnabled e BaseSku sono indicizzati e FreeTextStrings è indicizzato FTS.

Ricordo che funzionava bene prima.

Qualcuno può far luce su questo e suggerire alcune soluzioni?

file del piano di esecuzione è disponibile qui: http://wiki.webgear.co.nz/GetFile.aspx?File=Temp%5cSearch%20Test.sqlplan.zip

+0

Puoi mostrarci un piano di esecuzione dal tuo SQL Server? –

+0

Questi problemi si sono verificati dopo l'aggiornamento di SQL 2005 a SQL 2008. – Muxa

risposta

10

or è notoriamente lenta su SQL Server. È a dir poco aggravante.

prova a dividerla in due query con un union:

WITH AllProducts AS (
    select *, Row_Number() OVER (ORDER BY ProductId) AS RowNumber 
    from (
    SELECT  p.* 
    FROM  Product AS p 
    WHERE p.IsEnabled=1 AND 
     p.BaseSku = 'KPK-3020QWC-C' 
    UNION 
    SELECT  p.* 
    FROM  Product AS p 
    WHERE p.IsEnabled=1 AND 
     CONTAINS(p.FreeTextStrings, '"KPK-3020QWC*"') 
) 
) SELECT * FROM AllProducts   
    WHERE RowNumber BETWEEN 1 AND 20; 
+1

Esattamente, il "o" causa molto probabilmente una scansione della tabella sulla tabella del prodotto anche se ci sono indici su BaseSku e FreeTextStrings ... Un sindacato lo trasformerà per indicizzare seek + index scan ... (supponendo che ci siano indici che coprono quelle due colonne) – KristoferA

+0

L'ho provato e in effetti ha mostrato grandi miglioramenti.Proverò questa tecnica con la dichiarazione completa di sql. – Muxa

+0

Sì, questo l'ha risolto. Comunque penso che sia abbastanza strano che la stessa istruzione abbia funzionato molto velocemente in SQL 2005 e stia funzionando lentamente in SQL 2008. Potrebbe essere risolto nel prossimo service pack? – Muxa

1

Questo sembra funzionare bene:

WITH AllProducts AS (
    SELECT  p.*, Row_Number() OVER (ORDER BY ProductId) AS RowNumber 
    FROM  Product AS p 
    WHERE p.IsEnabled=1 AND 
    (
     CONTAINS(p.BaseSku, 'KPK-3020QWC-C') /* instead of p.BaseSku = 'KPK-3020QWC-C' */ 
     OR 
     CONTAINS(p.FreeTextStrings, '"KPK-3020QWC*"') 
    ) 
) SELECT * FROM AllProducts   
    WHERE RowNumber BETWEEN 1 AND 20; 

(ho già avuto BaseSku FTS-indicizzato)

0

Make sure all necessary indexes are in place. I ha avuto lo stesso problema con una clausola or in una delle mie query e la creazione di un INDICE NONCLUSTERED con le colonne INCLUDE ha corretto le prestazioni .

Dopo ulteriori test, è stato il INCLUDE colonne parte dell'indice che realmente risolto il problema di prestazioni. Ecco quello che ho fatto per determinare il problema e come risolvere il problema:

utilizzare il piano di esecuzione per aiutare a creare gli indici mancanti:

Senza l'indice della query stava prendendo 2+ min quando si dovrebbe avere ha funzionato in pochi millisecondi. Quindi ho confrontato i piani di esecuzione della query con e senza la clausola or in SSMS e non era chiaro cosa dovevo fare (principalmente a causa della mia mancanza di comprensione dei piani di esecuzione).

Ma se si guarda sopra il piano di esecuzione in testo verde, SSMS potrebbe suggerire di creare un indice non cluster. Hmm ... vale la pena sparare. Così ho creato l'indice e risolto il problema! È possibile fare clic con il tasto destro del mouse sulla query "CREATE INDEX" e selezionare "Dettagli indice mancanti ...". Questo aprirà una nuova scheda con la query completa per l'esecuzione. Dagli un nome.

Problemi correlati