LIKE usa index, CHARINDEX no?

22

Esta pregunta está relacionada con mi vieja pregunta . La consulta a continuación tardaba entre 10 y 15 segundos en ejecutarse:

SELECT [customer].[Customer name],[customer].[Sl_No],[customer].[Id]
FROM [company].dbo.[customer]
WHERE (Charindex('123456789',CAST([company].dbo.[customer].[Phone no] AS VARCHAR(MAX)))>0) 

En algunos artículos, vi que usar CASTy CHARINDEXno se beneficiará de la indexación. También hay algunos artículos que dicen que el uso LIKE '%abc%'no se beneficiará de la indexación, mientras LIKE 'abc%'que:

http://bytes.com/topic/sql-server/answers/81467-using-charindex-vs-like-where /programming/803783/sql-server-index-any-improvement-for -like-queries http://www.sqlservercentral.com/Forums/Topic186262-8-1.aspx#bm186568

En mi caso, puedo reescribir la consulta como:

SELECT [customer].[Customer name],[customer].[Sl_No],[customer].[Id]
FROM [company].dbo.[customer]
WHERE [company].dbo.[customer].[Phone no]  LIKE '%123456789%'

Esta consulta da el mismo resultado que la anterior. He creado un índice no agrupado para la columna Phone no. Cuando ejecuto esta consulta, se ejecuta en solo 1 segundo . Este es un gran cambio en comparación con los 14 segundos anteriores.

¿Cómo se LIKE '%123456789%'beneficia la indexación?

¿Por qué los artículos enumerados indican que no mejorará el rendimiento?

Intenté reescribir la consulta para usarla CHARINDEX, pero el rendimiento sigue siendo lento. ¿Por qué no CHARINDEXse beneficia de la indexación como parece que lo hace la LIKEconsulta?

Consulta usando CHARINDEX:

SELECT [customer].[Customer name],[customer].[Sl_No],[customer].[Id]
 FROM [Company].dbo.[customer]
 WHERE ( Charindex('9000413237',[Company].dbo.[customer].[Phone no])>0 ) 

Plan de ejecución:

ingrese la descripción de la imagen aquí

Consulta usando LIKE:

SELECT [customer].[Customer name],[customer].[Sl_No],[customer].[Id]
 FROM [Company].dbo.[customer]
 WHERE[Company].dbo.[customer].[Phone no] LIKE '%9000413237%'

Plan de ejecución:

Plan de consulta LIKE

Investigador de TI
fuente

Respuestas:

28

¿Cómo se beneficia LIKE '% 123456789%' de la indexación?

Solo un poco. El procesador de consultas puede escanear todo el índice no agrupado buscando coincidencias en lugar de toda la tabla (el índice agrupado). Los índices no agrupados son generalmente más pequeños que la tabla en la que están construidos, por lo que escanear el índice no agrupado puede ser más rápido.

La desventaja es que las columnas que necesita la consulta que no están incluidas en la definición del índice no agrupado deben buscarse en la tabla base, por fila.

El optimizador toma una decisión entre escanear la tabla (índice agrupado) y escanear el índice no agrupado con búsquedas, en función de las estimaciones de costos. Los costos estimados dependen en gran medida de la cantidad de filas que el optimizador espera que su LIKEo CHARINDEXpredicado para seleccionar.

¿Por qué los artículos enumerados indican que no mejorará el rendimiento?

Para una LIKEcondición que no comienza con un comodín, SQL Server puede realizar un escaneo parcial del índice en lugar de escanear todo. Por ejemplo, LIKE 'A%se puede evaluar correctamente probando solo registros de índice >= 'A'y < 'B'(los valores límite exactos dependen de la clasificación).

Este tipo de consulta puede usar la capacidad de búsqueda de los índices de b-tree: podemos ir directamente al primer registro >= 'A'usando el b-tree, luego escanear hacia adelante en orden de clave de índice hasta llegar a un registro que no pasa la < 'B'prueba. Dado que solo necesitamos aplicar la LIKEprueba a un número menor de filas, el rendimiento generalmente es mejor.

Por el contrario, LIKE '%Ano se puede convertir en una exploración parcial porque no sabemos por dónde empezar o terminar; cualquier registro podría terminar 'A', por lo que no podemos mejorar escaneando todo el índice y probando cada fila individualmente.

Intenté reescribir la consulta para usarla CHARINDEX, pero el rendimiento sigue siendo lento. ¿Por qué no CHARINDEXse beneficia de la indexación como parece que hace la consulta LIKE?

El optimizador de consultas tiene la misma opción entre escanear la tabla (índice agrupado) y escanear el índice no agrupado (con búsquedas) en ambos casos.

La elección se realiza entre los dos en función de la estimación de costos . Sucede que SQL Server puede producir una estimación diferente para los dos métodos. Para la LIKEforma de la consulta, la estimación puede usar estadísticas de cadena especiales para producir una estimación razonablemente precisa. El CHARINDEX > 0formulario produce una estimación basada en una suposición.

Las diferentes estimaciones son suficientes para que el optimizador elija un Análisis de CHARINDEXíndice agrupado y un Análisis de índice no agrupado con búsquedas para LIKE. Si obliga a la CHARINDEXconsulta a utilizar el índice no agrupado con una pista, obtendrá el mismo plan que para LIKE, y el rendimiento será casi el mismo:

SELECT
    [Customer name],
    [Sl_No],
    [Id]
FROM dbo.customer WITH (INDEX (f))
WHERE 
    CHARINDEX('9000413237', [Phone no]) >0;

El número de filas procesadas en tiempo de ejecución será el mismo para ambos métodos, es solo que el LIKEformulario produce una estimación más precisa en este caso, por lo que el optimizador de consultas elige un mejor plan.

Si necesita realizar LIKE %thing%búsquedas a menudo, es posible que desee considerar una técnica sobre la que escribí en Trigram Wildcard String Search en SQL Server .

Paul White dice GoFundMonica
fuente
16

SQL Server mantiene estadísticas sobre las subcadenas en columnas de cadena en forma de intentos que pueden ser utilizados por la LIKEconsulta pero no por el CHARINDEX.

Consulte la sección Estadísticas de resumen de cadena para obtener más información al respecto.

Un par de advertencias importantes son que cualquier escape de comodines debe hacerse con la técnica patentada de corchetes en lugar de la ESCAPEpalabra clave y que para cadenas de más de 80 caracteres solo se usan los primeros y últimos 40 caracteres.

WHERE ( Charindex('9000413237',[Company].dbo.[customer].[Phone no])>0 ) 

solo usará la suposición estándar para un predicado de desigualdad de que se devolverá el 30% de las filas.

La LIKEconsulta (en su caso) presumiblemente estima que muchas menos filas coincidirán con el predicado.

Tenga en cuenta que el comodín principal todavía impide una búsqueda de índice. Todavía se escanea un índice completo, pero utiliza uno diferente que es más estrecho que el índice agrupado. El índice más estrecho no cubre todas las columnas utilizadas por la consulta, por lo que el segundo plan requiere una búsqueda clave para recuperar las columnas que faltan.

Es poco probable que este plan se elija con una estimación del 30%. SQL Server considerará que es más barato escanear todo el índice agrupado y evitar tantas búsquedas. Consulte este artículo sobre el punto de inflexión para ver ejemplos adicionales.

Martin Smith
fuente
No estoy claro con su explicación. ¿Estás diciendo que usar like es mejor que charindex?
Investigador de TI
3
@ITresearcher: sí, potencialmente, en lugar de usar una suposición general de cuántas filas coincidirán con la condición ( 30%), puede ver el LIKEpatrón suministrado y las estadísticas de resumen de cadena y obtener una estimación más precisa. Armado con eso, podría elegir un plan diferente y más apropiado.
Martin Smith
3
... o, en el "peor de los casos", el mismo plan.
Aaron Bertrand