FREETEXT Query è lento - include TOP e ORDER BY
-
02-10-2019 - |
Domanda
La tabella prodotto ha 700K record in esso. La query:
SELECT TOP 1 ID,
Name
FROM Product
WHERE contains(Name, '"White Dress"')
ORDER BY DateMadeNew desc
richiede circa 1 minuto per l'esecuzione. V'è un indice non cluster in DateMadeNew e FREETEXT indice sul nome.
Se rimuovo TOP 1 o ORDER BY -. Ci vogliono meno di 1 secondo per eseguire
Ecco il link al piano di esecuzione. http://screencast.com/t/ZDczMzg5N
appare come FullTextMatch ha più di 400K esecuzioni. Perché sta succedendo? Come può essere reso più veloce?
AGGIORNAMENTO 5/3/2010
appare come cardinalità è fuori di colpo sulle ricerche FREETEXT a più di parole:
Optimizer stima che ci siano 28K record corrispondenti 'White Dress', mentre in realtà solo 1 non c'è. http://screencast.com/t/NjM3ZjE4NjAt
Se sostituisco 'White Dress' con 'White', il numero stimato è di '27, 951' , mentre il numero reale è '28, 487' , che è molto meglio.
Sembra Optimizer sta usando solo la prima parola nella frase ricercata cardinalità.
Soluzione
Modifica
http://technet.microsoft.com/en- us / library / cc721269.aspx # _Toc202506240
La cosa più importante è che la corretto tipo di join viene raccolto per query full-text. Cardinalità la stima sul FulltextMatch STVF è molto importante per il piano giusto. Quindi la prima cosa da controllare è la FulltextMatch stima di cardinalità. Questo è il numero stimato di colpi nel indice per la ricerca full-text corda. Ad esempio, nella query in Figura 3 questo dovrebbe essere vicino al il numero di documenti contenenti le termine ‘parola’. Nella maggior parte dei casi si deve essere molto accurata, ma se la stima era fuori da un lungo cammino, si potrebbe generare piani cattivi. La stima per la singoli termini è normalmente molto buona, ma la stima più termini quali frasi o e query è più complessa dal momento che non è possibile sapere che cosa l'intersezione dei termini nell'indice sarà basato sulla frequenza del termini nell'indice. Se la cardinalità la stima è buono, un cattivo piano di probabilmente è causata dalla query modello di costo ottimizzatore. L'unico modo per risolvere il problema piano è quello di utilizzare una query AVVISO Per forzare un certo tipo di join o OPTIMIZE FOR.
Quindi, semplicemente, non può conoscere dalle informazioni che memorizza se i 2 termini di ricerca insieme sono suscettibili di essere del tutto indipendente o comunemente trovati insieme. Forse si dovrebbe avere 2 procedure distinte una per le query sola parola che si lascia l'ottimizzatore di fare il suo roba e uno per le procedure a più di parole che si forza un piano di "abbastanza buono", a (sys.dm_fts_index_keywords potrebbe aiutare se non si desidera un taglia unica piano).
. NB: La procedura di sola parola sarebbe probabilmente necessario l'opzione WITH RECOMPILE guardando questo pezzo di questo articolo
In SQL Server 2008 la ricerca full-text abbiamo la possibilità di modificare il piano che viene generato sulla base di una stima di cardinalità del termine di ricerca utilizzato. Se il piano di query è fisso (come in una query con parametri all'interno di una stored procedure), questo passo non avviene. Pertanto, il piano compilato serve sempre questa domanda, anche se questo piano non è l'ideale per un determinato termine di ricerca.
risposta originale
Il nuovo piano appare ancora piuttosto male però. Sembra che esso è solo tornando 1 fila dalla parte piena di query di testo, ma la scansione di tutti i 770159 righe della tabella Product.
Come funziona questo esegue?
CREATE TABLE #tempResults
(
ID int primary key,
Name varchar(200),
DateMadeNew datetime
)
INSERT INTO #tempResults
SELECT
ID, Name, DateMadeNew
FROM Product
WHERE contains(Name, '"White Dress"')
SELECT TOP 1
*
FROM #tempResults
ORDER BY DateMadeNew desc
Altri suggerimenti
Non riesco a vedere il piano di esecuzione legata, la polizia di rete che stanno bloccando, quindi questo è solo una supposizione ...
se è in esecuzione veloce senza l'TOP
e ORDER BY
, prova a fare questo:
SELECT TOP 1
*
FROM (SELECT
ID, Name, DateMadeNew
FROM Product
WHERE contains(Name, '"White Dress"')
) dt
ORDER BY DateMadeNew desc
appare come FullTextMatch ha più di 400K esecuzioni. Perché sta succedendo?
Dal momento che si dispone di un indice combinato con TOP 1
, ottimizzatore pensa che sarà meglio per attraversare l'indice, controllando ogni record per la voce.
Come può essere reso più veloce?
Se l'aggiornamento delle statistiche non aiuta, prova ad aggiungere un suggerimento per la vostra richiesta:
SELECT TOP 1 *
FROM product pt
WHERE CONTAINS(name, '"test1"')
ORDER BY
datemadenew DESC
OPTION (HASH JOIN)
Questo costringerà il motore di utilizzare un algoritmo HASH JOIN
per unire il vostro tavolo e l'output della query full-text.
testo completo è considerata come una sorgente remota restituisce l'insieme di valori indicizzati da KEY INDEX
previsto nella definizione FULLTEXT INDEX
.
Aggiornamento:
Se i vostri usi ORM
parametrizzate query, è possibile creare una guida di piano.
- Usa Profiler per intercettare la query che il
ORM
invia Verbatim - Genera un corretto piano di in
SSMS
utilizzando i suggerimenti e salvarla comeXML
- Usa
sp_create_plan_guide
con unaOPTION USE PLAN
per forzare l'ottimizzatore utilizzare sempre questo piano.
ho avuto lo stesso problema in precedenza.
Il rendimento dipende da quale unico indice che si sceglie per l'indicizzazione full-text.
Il mio tavolo ha due colonne uniche -. ID
e article_number
La query:
select top 50 id, article_number, name, ...
from ARTICLE
CONTAINS(*,'"BLACK*" AND "WHITE*"')
ORDER BY ARTICLE_NUMBER
Se l'indice testo completo è collegato ad ID
allora è lento a seconda della parola cercata.
Se l'indice testo completo è collegato all'indice ARTICLE_NUMBER UNIQUE
poi è stato sempre veloce.
Ho una migliore soluzione.
I. prima panoramica di Let proposto soluzioni come anche possono essere utilizzati in alcuni casi:
-
OPTION (hash join) - non è buono come si può ottenere errore di "processore di query potrebbe non produrre un piano di query a causa degli hint definiti nella query Reinvia la query senza specificare alcun suggerimento e senza. utilizzando SET FORCEPLAN. "
-
Seleziona TOP 1 * FROM (ORIGINAL_SELECT) ORDER BY ... - non è buono, quando è necessario utilizzare impaginare i risultati da voi ORIGINAL_SELECT
-
sp_create_plan_guide - non è buona, come per l'uso plan_guide è necessario salvare piano di un'individuazione precisa SQL, questo non funzionerà per le dichiarazioni SQL dinamiche (ad esempio generati da ORM)
II. La mia soluzione contiene due parti 1. Auto unirsi tabella utilizzata per la ricerca Full Text 2. HASH Utilizzare MS SQL JOIN suggerimenti MSDN JOIN suggerimenti
Il tuo SQL:
SELECT TOP 1 ID, Name FROM Product WHERE contains(Name, '"White Dress"')
ORDER BY DateMadeNew desc
Dovrebbe essere riscritto come:
SELECT TOP 1 p.ID, p.Name FROM Product p INNER HASH JOIN Product fts ON fts.ID = p.ID
WHERE contains(fts.Name, '"White Dress"')
ORDER BY p.DateMadeNew desc
Se si utilizza NHibernate con / senza Castello record attivi, ho risposto in posta come intercettore scrittura per modificare la query per sostituire INNER JOIN da INNER JOIN HASH
Un paio di riflessioni su questo:
1) Avete aggiornato le statistiche sul tavolo del prodotto? Sarebbe utile per vedere le stime e il numero effettivo di righe sulle operazioni anche lì.
2) Quale versione di SQL Server stai usando? Ho avuto un problema simile con SQL Server 2008 che si è rivelato essere niente di più che non avere il Service Pack 1 installato. Installare SP1 e una query FREETEXT che stava prendendo un paio di minuti (a causa di un enorme numero di esecuzioni effettive contro reale) è andato giù a prendere un secondo.