La consulta de SQL Server es lenta cuando está paginada

14

Veo un comportamiento extraño con la siguiente consulta T-SQL en SQL Server 2012:

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

Ejecutar esta consulta solo me da unos 1.300 resultados en menos de dos segundos (hay un índice de texto completo Name)

Sin embargo, cuando cambio la consulta a esto:

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

Me lleva más de 20 segundos darme 10 resultados.

La siguiente consulta es aún peor:

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

¡Tarda más de 1.5 minutos en completarse!

¿Algunas ideas?

Plan lento

Lento

Plan rapido

Rápido

vrs
fuente
¿Qué sucede si cambia su segunda consulta a SELECT TOP 10 * .... ORDER BY Name?
Lamak
¿En qué columnas se hace el índice IX_PersonSearch ...? Está obteniendo una búsqueda de clave porque está seleccionando * de la tabla y el índice utilizado no contiene todas las columnas de salida. Creo que debe seleccionar solo las columnas que necesita y luego incluirlas en el índice no agrupado como columnas incluidas, no columnas de índice.
Marcel N.
¿Puedes publicar tus índices en la tabla (crear script)?
3
El ID siempre se incluye en cada índice no agrupado. Esta es la forma en que SQL Server puede realizar búsquedas clave (por ID).
Usr
1
Lo que olvidé mencionar: cuando hago la misma consulta con LIKE en lugar de CONTAINS, también es rápido. (Paginado o no)

Respuestas:

7

Como solo desea el TOP 10ordenado por nombre, cree que será más rápido trabajar en el índice namey ver si cada fila coincide con el CONTAINS(Name, '"John" AND "Smith"') )predicado.

Presumiblemente, se necesitan muchas más filas para encontrar las 10 coincidencias requeridas de lo que se espera y este problema de cardinalidad se ve agravado por la cantidad de búsquedas clave.

Un truco rápido para detenerlo usando este plan sería cambiar el ORDER BYa ORDER BY Name + ''aunque usarlo CONTAINSTABLEjunto con FORCE ORDERtambién debería funcionar.

Martin Smith
fuente
3

Esto se parece a la clásica estimación de la selectividad. No estoy seguro de qué se puede hacer al respecto, ya que el "controlador" de la consulta es una búsqueda de texto completo que no puede aumentar con estadísticas.

Intente reescribir el where containspredicado a un inner join containstable( CONTAINSTABLE ) y aplique sugerencias de orden de unión para forzar la forma del plan.

Esa no es una solución perfecta porque tiene problemas de mantenimiento, pero no puedo ver otra forma.

usr
fuente
Gracias por tu respuesta, lo intenté. Sin embargo, el mismo resultado: cuando no se utiliza la paginación, la consulta es realmente rápida. Al Paginar, de repente se vuelve muy lento nuevamente: /
Ok, ¿puedes publicar el plan como una imagen y tu consulta? Supongo que todavía no logramos generar la forma deseada.
usr
3

Me las arreglé para resolver el problema:

Como dije en la pregunta, había índices en todas las columnas + estadísticas para cada columna. (Debido a las consultas LIKE heredadas) Eliminé todos los índices y estadísticas, agregué la búsqueda de texto completo y voilà, la consulta se volvió realmente rápida.

Parece que los índices llevaron a un plan de ejecución diferente.

¡Muchas gracias a todos por su ayuda!

vrs
fuente
1
Supongo que eliminar el índice por completo es una forma de evitar que se use.
Martin Smith