2009-04-29 15 views
18

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 nombres parciales, etc. SQL Server 2005SQL Server Index: ¿alguna mejora para las consultas LIKE?

Agregar un index en estos campos varchar ayuda en términos de seleccionar el rendimiento de la consulta cuando se utiliza LIKE o básicamente ignora los índices y realiza un análisis completo en esos casos?

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

Respuesta

18

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á.

+0

Gracias, eso es lo que pensé desafortunadamente. He eliminado algunas de las cláusulas LIKE para ayudar a acelerar un poco. – schooner

2

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

Tiene 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 procesar previamente 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 donde el uso de disparadores, en lugar de código de aplicación, sería mucho preferido.

Debo enfatizar que esta no es realmente una técnica óptima y solo debe 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 como el escaneo realmente es inaceptable). También es probable que produzca dolores de cabeza de mantenimiento más adelante en la línea.

8

La única otra forma (aparte de usar 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, podría funcionar un índice .

Si sus necesidades son tales que hay que tener comodines en ambos extremos de su término de búsqueda, usted está de suerte ...

Marc

+0

¿Funciona solo para 'LIKE ABC%', o funciona también para 'LIKE% ABC'? Además, tengo curiosidad por saber por qué funciona con un comodín de un solo lado ... ¿Podrías dar más detalles sobre eso, por favor? –

+0

@ TomPažourek: bueno, imagina una guía telefónica (si eres lo suficientemente mayor como para recordar qué fue eso :-); si estás buscando a alguien cuyo apellido ** comienza con ** 'Smi', encontrarás' Smith' y 'Smithers' etc. con bastante rapidez. Pero si busca a alguien cuyo apellido ** contiene ** (en cualquier parte del nombre), p. Ej. 'chuk', tener la lista ordenada de nombres (que es lo que realmente es ** un ** índice) realmente no te ayuda mucho, todavía tienes que desplazarte sobre ** todos los nombres ** para encontrar aquellos con esa cadena en su nombre –

+0

Gracias. :-) ¿Sabes qué estructura de datos se usa? ¿Es alguna forma de trie? ¿Eso significa que '% ABC' no usará ningún índice? Usted solo mencionó que el comodín en ambos extremos no funcionará. ¿Funcionará el comodín en el extremo derecho? –

-2

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

11

Potencialmente puede ver mejoras en el rendimiento mediante la adición de índice (es), que depende mucho de las características específicas :)

¿Qué parte del tamaño total de la fila son sus columnas hendidas? ¿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 devolver), y las columnas predicadas son una porción más pequeña de todo el tamaño de fila, 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í se muestra un ejemplo en el que el tamaño total de la fila es mucho mayor que el tamaño de la columna para buscar a través de:

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 nos fijamos en el plan de ejecución real se puede ver el motor de escaneado del í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 su cuenta: 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. P.ej. 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 seguridad obtendrá una mejor exploración de tabla.

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

HTH! -Adrian

+0

También considere INCLUIR índices si devuelve un subconjunto de columnas en una tabla ancha. –

+0

Considera también los datos que estás consultando también. Por ejemplo, agregar un Índice filtrado que excluya cadenas nulas y/o vacías y luego usar ese índice en su consulta ayudará mucho al rendimiento. El índice será más pequeño y menos para LIKE para escanear. –

Cuestiones relacionadas