Índice de SQL Server: ¿alguna mejora para las consultas LIKE?

votos
20

Tenemos una consulta que se ejecuta en una tabla bastante grande que desafortunadamente necesita usar LIKE '% ABC%' en un par de campos varchar para que el usuario pueda buscar en nombres parciales, etc. SQL Server 2005

¿Sería útil agregar un índice en estos campos varchar en términos de seleccionar el rendimiento de la consulta al usar LIKE o básicamente ignorar los índices y hacer un escaneo completo en esos casos?

¿Alguna otra forma posible de mejorar el rendimiento al usar LIKE?

Publicado el 29/04/2009 a las 20:03
fuente por usuario
En otros idiomas...                            


5 respuestas

votos
20

Solo si agrega la búsqueda de texto completo a esas columnas y utiliza las capacidades de consulta de texto completo de SQL Server.

De lo contrario, no, un índice no ayudará.

Respondida el 29/04/2009 a las 20:07
fuente por usuario

votos
10

Puede ver mejoras en el rendimiento agregando índices, depende mucho de los detalles :)

¿Cuánto del tamaño total de la fila son sus columnas predicadas? ¿Cuántas filas espera que coincidan? ¿Necesita devolver todas las filas que coincidan con el predicado, o solo la parte superior 1 o las n filas superiores?

Si está buscando valores con alta selectividad / unicidad (tan pocas filas para regresar), y las columnas predicadas son una porción pequeña del tamaño de la fila completa, un índice podría ser bastante útil. Seguirá siendo un análisis, pero su índice se ajustará a más filas por página que la tabla de origen.

Aquí hay un ejemplo donde el tamaño total de la fila es mucho mayor que el tamaño de la columna para buscar:

create table t1 (v1 varchar(100), b1 varbinary(8000))
go
--add 10k rows of filler
insert t1 values ('abc123def', cast(replicate('a', 8000) as varbinary(8000)))
go 10000
--add 1 row to find
insert t1 values ('abc456def', cast(replicate('a', 8000) as varbinary(8000)))
go

set statistics io on 
go
select * from t1 where v1 like '%456%'
--shows 10001 logical reads

--create index that only contains the column(s) to search across
create index t1i1 on t1(v1)
go
select * from t1 where v1 like '%456%'
--or can force to 
--shows 37 logical reads

Si observa el plan de ejecución real, puede ver que el motor escaneó el índice e hizo una búsqueda de marcador en la fila correspondiente. O puede decirle directamente al optimizador que use el índice, si no ha decidido usar este plan por sí mismo: seleccione * de t1 con (índice (t1i1)) donde v1 como '% 456%'

Si tiene un grupo de columnas para buscar solo unas pocas que son altamente selectivas, puede crear múltiples índices y usar un enfoque de reducción. Por ejemplo, primero determine un conjunto de ID (o cualquiera que sea su PK) de su índice altamente selectivo, luego busque las columnas menos selectivas con un filtro contra ese pequeño conjunto de PK.

Si siempre necesita devolver un gran conjunto de filas, casi con toda seguridad mejorará con una exploración de tabla.

Por lo tanto, las posibles optimizaciones dependen mucho de los detalles de la definición de su tabla y de la selectividad de sus datos.

HTH! -Adrian

Respondida el 30/04/2009 a las 18:00
fuente por usuario

votos
8

La única otra forma (aparte de utilizar la indexación de texto completo) de mejorar el rendimiento es usar "LIKE ABC%", no agregue el comodín en ambos extremos del término de búsqueda; en ese caso, un índice podría funcionar.

Si sus requisitos son tales que debe tener comodines en ambos extremos del término de búsqueda, no tiene suerte ...

Bagazo

Respondida el 29/04/2009 a las 21:23
fuente por usuario

votos
2

Like '% ABC%' siempre realizará un escaneo completo de la tabla. No hay forma de evitar eso.

Tienes un par de enfoques alternativos. En primer lugar, búsqueda de texto completo, está realmente diseñado para este tipo de problema, así que lo veré primero.

Alternativamente, en algunas circunstancias podría ser apropiado desnormalizar los datos y preprocesar los campos de destino en tokens apropiados, luego agregar estos posibles términos de búsqueda en una tabla de búsqueda separada de uno a muchos. Por ejemplo, si mis datos siempre constaban de un campo que contenía el patrón 'AAA / BBB / CCC' y mis usuarios estaban buscando en BBB, lo pondría en la inserción / actualización (y eliminaría en la eliminación). Este también sería uno de esos casos en los que sería más preferible usar desencadenadores, en lugar de código de aplicación .

Debo enfatizar que esta no es realmente una técnica óptima y solo debería usarse si los datos coinciden con el enfoque y por alguna razón no desea utilizar la búsqueda de texto completo (y el rendimiento de la base de datos en el escaneo similar es realmente inaceptable). También es probable que produzca dolores de cabeza de mantenimiento más adelante en la línea.

Respondida el 29/04/2009 a las 20:25
fuente por usuario

votos
-3

crea estadísticas en esa columna. sql srever 2005 ha optimizado la búsqueda en cadenas, por lo que puede beneficiarse de eso.

Respondida el 29/04/2009 a las 22:48
fuente por usuario

Cookies help us deliver our services. By using our services, you agree to our use of cookies. Learn more