10

Ho una semplice query che si basa su due tavoli full-text indicizzate, ma funziona estremamente lento quando ho il CONTIENE in combinazione con tutte le ulteriori O ricerca. Come si vede nel piano di esecuzione, le due ricerche a testo integrale schiacciono le prestazioni. Se interrogo solo 1 dei CONTAINS, o nessuno dei due, la query è inferiore al secondo, ma nel momento in cui aggiungi O nel mix, la query diventa sfortunata.O ricerche con CONTIENE Brings Query per Crawl

I due tavoli non sono niente di speciale, non sono eccessivamente larghi (42 col in uno, 21 nell'altro, forse 10 colli sono indicizzati FT in ognuno) o contengono anche molti record (36k recs nel più grande di il due).

sono stato in grado di risolvere le prestazioni suddividendo i due CONTIENE ricerche nella propria SELEZIONA query e quindi UNION i tre insieme. Questa soluzione UNION è la mia unica speranza?

Grazie.

SELECT  a.CollectionID 
FROM  collections a 
INNER JOIN determinations b ON a.CollectionID = b.CollectionID 
WHERE  a.CollrTeam_Text LIKE '%fa%' 
      OR CONTAINS(a.*, '"*fa*"') 
      OR CONTAINS(b.*, '"*fa*"') 

del piano di esecuzione (che ho bisogno di più la reputazione prima di poter postare l'immagine): http://yfrog.com/7dslowcontainsj http://desmond.yfrog.com/Himg265/scaled.php?tn=0&server=265&filename=slowcontains.jpg&xsize=640&ysize=640

+1

Vorrei sottolineare @ChiragRoy afferma che si tratta di un problema noto con SQL2008/R2 con un caso PSS aperto. Ma sono curioso che qualcun altro si sia imbattuto nel problema e abbia trovato una soluzione alternativa o un motivo per il problema. – scolja

+1

Non sono abbastanza sicuro di cosa sia il protocollo per contrassegnare una singola risposta come risposta. In questo caso, UNION risolve definitivamente il problema, ma sembrerebbe che io possa risolvere il problema e ottenere prestazioni migliori con CONTAINSTABLE. Apprezzo molto il feedback di tutti sulla domanda. – scolja

risposta

6

Sarei curioso di vedere se un LEFT JOIN ad un CONTAINSTABLE equivalente avrebbe eseguito meglio. Qualcosa di simile:

SELECT  a.CollectionID 
FROM  collections a 
INNER JOIN determinations b ON a.CollectionID = b.CollectionID 
LEFT JOIN CONTAINSTABLE(a, *, '"*fa*"') ct1 on a.CollectionID = ct1.[Key] 
LEFT JOIN CONTAINSTABLE(b, *, '"*fa*"') ct2 on b.CollectionID = ct2.[Key] 
WHERE  a.CollrTeam_Text LIKE '%fa%' 
      OR ct1.[Key] IS NOT NULL 
      OR ct2.[Key] IS NOT NULL 
+2

Incredibile, prestazioni ancora migliori. Anche in questo caso DISTINCT doveva essere aggiunto e CONTAINSTABLE aveva bisogno dei nomi effettivi delle tabelle, ma con alcune modifiche minori funzionava perfettamente. Confronto dei costi tra i 3 metodi: 29%, 32% e 38% (CONTAINSTABLE, LEFT OUTER JOIN, quindi UNION). Logical legge ora 1/5 della query UNION. Molto bene. – scolja

+0

se hai solo bisogno di 'CollectionID', quindi non hai nemmeno bisogno di fare i join. Puoi usare 'ct1.Key come CollectionID' –

2

Stavo per suggerire a UNION ciascuno come loro interrogazione, ma come ho letto la tua domanda ho visto che l'hai trovato. Non riesco a pensare a un modo migliore, quindi se aiuta a usarlo. Il metodo UNION è un approccio comune a una query con scarse prestazioni che presenta diverse condizioni OR in cui ciascuna esegue correttamente le proprie.

+0

+1 Vorrei anche suggerire UNION. Come nota, direi che UNION è la soluzione * giusta *, non la soluzione alternativa. –

+0

Grazie, la rassicurazione che l'approccio UNION è molto utile; Inoltre non fa male che la query funzioni bene ora per l'avvio. – scolja

+1

E se le due istruzioni unione si escludono a vicenda ogni volta, quindi utilizzare UNION ALL per ulteriori imporvi prestazioni. – HLGEM

1

Probabilmente userei l'UNION. Se siete veramente contro di esso, si potrebbe provare qualcosa di simile:

SELECT a.CollectionID 
FROM collections a 
    LEFT OUTER JOIN (SELECT CollectionID FROM collections WHERE CONTAINS(*, '"*fa*"')) c 
    ON c.CollectionID = a.CollectionID 
    LEFT OUTER JOIN (SELECT CollectionID FROM determinations WHERE CONTAINS(*, '"*fa*"')) d 
    ON d.CollectionID = a.CollectionID 
WHERE a.CollrTeam_Text LIKE '%fa%' 
    OR c.CollectionID IS NOT NULL 
    OR d.CollectionID IS NOT NULL 
+0

Ho dovuto aggiungere DISTINCT, ma questo in realtà comporta un leggero miglioramento delle prestazioni rispetto al metodo UNION.Il confronto dei costi è compreso tra il 46% e il 54% con circa 2/3 del numero di letture logiche. Intrigante! – scolja

0

abbiamo esperienza lo stesso identico problema e, al momento, messi giù alla nostra interrogazione essere correttamente formulato - che SQL 2005 aveva cerchiamo di farla franca, ma il 2008 non avrebbe fatto.

Alla fine, abbiamo diviso la query in 2 SELECT che sono stati chiamati utilizzando un IF. Sono contento che qualcun altro abbia avuto lo stesso problema e che sia un problema noto. Stavamo visualizzando le query su un tavolo con ~ 150.000 righe + testo completo da < 1 secondo (2005) a 30+ secondi (2008).

+1

Esattamente! In origine, questa query funzionava correttamente su un computer SQL 2000, ma una volta passati a SQL 2008, questo è apparso. Benvenuti nel nostro nuovo club. – scolja