FreeText de consulta es lento - incluye TOP y ORDER BY
-
02-10-2019 - |
Pregunta
La tabla Producto 700K tiene registros en el mismo. La consulta:
SELECT TOP 1 ID,
Name
FROM Product
WHERE contains(Name, '"White Dress"')
ORDER BY DateMadeNew desc
tarda aproximadamente 1 minuto para correr. Hay un índice no agrupado en el índice DateMadeNew y FreeText en Nombre.
Si quito TOP 1 o Ordenar por -. Se tarda menos de 1 segundo para correr
Aquí está el enlace al plan de ejecución. http://screencast.com/t/ZDczMzg5N
Las apariencias como FullTextMatch cuenta con más de 400 mil ejecuciones. ¿Por qué está pasando esto? ¿Cómo se puede hacer más rápido?
ACTUALIZACIÓN 5/3/2010
Las apariencias como cardinalidad está fuera de control en las búsquedas de texto libre de múltiples palabras:
Optimizador estima que hay 28K registros que contengan 'vestido blanco', mientras que en realidad sólo hay 1. http://screencast.com/t/NjM3ZjE4NjAt
Si sustituyo 'vestido blanco' con 'White', el número estimado es de 27, 951' , mientras que el número real es de '28, 487' , que es mucho mejor.
Parece que Optimizer está utilizando sólo la primera palabra en la frase que se busca cardinalidad.
Solución
Editar
http://technet.microsoft.com/en- es / library / cc721269.aspx # _Toc202506240
Lo más importante es que el correcta tipo de combinación es recogido por consulta de texto completo. cardinalidad la estimación de la FulltextMatch STVF es muy importante para el plan de la derecha. Así que la primera cosa a comprobar es la la estimación de cardinalidad FulltextMatch. Este es el número estimado de éxitos en el índice para la búsqueda de texto completo cuerda. Por ejemplo, en la consulta de La figura 3 esto debe estar cerca de la número de documentos que contengan la ‘Palabra’ plazo. En la mayoría de los casos lo que debería ser muy precisa, pero si la estimación estaba fuera por un largo camino, usted podría generar malos planes. La estimación para términos individuales es normalmente muy bueno, pero la estimación de varios términos, tales como frases o y consultas resulta más complejo ya que no es posible saber lo la intersección de los términos en el índice se basará en la frecuencia de la términos en el índice. Si la cardinalidad estimación es bueno, un mal plan probablemente es causada por la consulta modelo de costos optimizador. La única manera de solucionar el problema plan es utilizar una consulta alusión a la fuerza de un cierto tipo de combinación u optimizar PARA.
Por lo tanto, simplemente no puede saber a partir de la información que almacena si los términos de búsqueda 2 juntos son propensos a ser bastante independiente o comúnmente encontrado juntos. Tal vez debería tener 2 procedimientos separados uno para consultas de una sola palabra que permita que el optimizador de hacer sus cosas en y uno para los procedimientos de múltiples palabras que se fuerza un plan "lo suficientemente bueno" en (sys.dm_fts_index_keywords podría ayudar si usted no quiere una una talla para todos plan).
Nota:. Su único procedimiento palabra probablemente necesitará la opción CON RECOMPILE mirando este bit del artículo
En SQL Server 2008 búsqueda de texto completo que tenemos la capacidad de alterar el plan que se genera en base a una estimación de cardinalidad del término de búsqueda utilizado. Si se fija el plan de consulta (como lo es en una consulta con parámetros dentro de un procedimiento almacenado), este paso no se realiza. Por lo tanto, el plan compilado siempre sirve esta consulta, incluso si este plan no es ideal para un término de búsqueda determinado.
Respuesta original
Su nuevo plan todavía se ve bastante mala. Parece como si sólo se está volviendo 1 fila de la parte completa consulta de texto, pero el escaneo de todos los 770159 filas de la tabla del producto.
¿Cómo realizar esta?
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
Otros consejos
No se puede ver el plan de ejecución vinculado, la policía de red que están bloqueando, así que esto es sólo una suposición ...
si se está ejecutando rápido sin la TOP
y ORDER BY
, trate de hacer esto:
SELECT TOP 1
*
FROM (SELECT
ID, Name, DateMadeNew
FROM Product
WHERE contains(Name, '"White Dress"')
) dt
ORDER BY DateMadeNew desc
Las apariencias como FullTextMatch cuenta con más de 400 mil ejecuciones. ¿Por qué sucede esto?
Ya que tiene un índice combinado con TOP 1
, optimizador piensa que va a ser mejor para atravesar el índice, comprobando cada registro para la entrada.
¿Cómo se puede hacer más rápido?
Si la actualización de las estadísticas no ayuda, trate de añadir un toque a su consulta:
SELECT TOP 1 *
FROM product pt
WHERE CONTAINS(name, '"test1"')
ORDER BY
datemadenew DESC
OPTION (HASH JOIN)
Esto obligará a que el motor se utilice un algoritmo HASH JOIN
a unirse a su mesa y el resultado de la consulta de texto completo.
Texto completo es considerado como una fuente remota devolver el conjunto de valores indexados por KEY INDEX
proporcionado en la definición FULLTEXT INDEX
.
Actualización:
Si sus usos ORM
parametrizar consultas, puede crear una guía de plan.
- Uso de perfiles para interceptar la consulta que envía el
ORM
textualmente - Generar un plan correcto en
SSMS
uso de sugerencias y guardarlo comoXML
- Uso
sp_create_plan_guide
con unOPTION USE PLAN
para forzar al optimizador utilice siempre este plan.
Yo tenía el mismo problema anterior.
El rendimiento depende de qué índice único que elija para la indexación de texto completo.
La tabla tiene dos columnas únicas -. ID
y article_number
La consulta:
select top 50 id, article_number, name, ...
from ARTICLE
CONTAINS(*,'"BLACK*" AND "WHITE*"')
ORDER BY ARTICLE_NUMBER
Si el índice de texto completo está conectado a ID
entonces es lenta en función de las palabras buscadas.
Si el índice de texto completo está conectado al índice ARTICLE_NUMBER UNIQUE
entonces era siempre rápido.
Tengo una mejor solución.
I. primera visión general de Let propone soluciones, ya que también se pueden usar en algunos casos:
-
OPCIÓN (hash) - no es bueno ya que puede tener errores "procesador de consultas no pudo producir un plan de consulta a causa de las pistas definidas en esta consulta Volver a enviar la consulta sin especificar ninguna pista y fuera. utilizando FORCEPLAN SET ".
-
SELECT * FROM TOP 1 (ORIGINAL_SELECT) ORDER BY ... - no es bueno, cuando es necesario utilizar la paginación de resultados que ORIGINAL_SELECT
-
sp_create_plan_guide - no es bueno, en cuanto a su uso plan_guide tienes que salvar el plan de una identificación exacta de SQL, este no funcionará para las sentencias de SQL dinámico (por ejemplo, generados por ORM)
II. Mi solución contiene de dos partes 1. Auto unirse tabla que se utiliza para la búsqueda de texto completo 2. Uso HASH MS SQL sugerencias de combinación MSDN sugerencias de combinación
Su SQL:
SELECT TOP 1 ID, Name FROM Product WHERE contains(Name, '"White Dress"')
ORDER BY DateMadeNew desc
En caso de ser reescrita como:
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
Si está utilizando NHibernate con / sin Castillo activos Records, he respondido en posterior cómo interceptor de escritura para modificar la consulta para reemplazar INNER JOIN por interno hash
Un par de pensamientos en este caso:
1) ¿Ha actualizado las estadísticas de la tabla del producto? Sería útil para ver las estimaciones y el número real de filas en las operaciones allí también.
2) ¿Qué versión de SQL Server está utilizando? Tenía un problema similar con SQL Server 2008 que resultó ser nada más que no tener instalado el Service Pack 1. Instalar el SP1 y una consulta de texto libre que se estaba produciendo un par de minutos (debido a un gran número de ejecuciones reales contra real) descendieron a tomar un segundo.