21

Tengo una enorme tabla con 2 columnas: Id y Título. Id es bigint y soy libre de elegir el tipo de columna Título: varchar, char, text, whatever. El título de columna contiene cadenas de texto aleatorias como "abcdefg", "q", "allyourbasebelongtous" con un máximo de 255 caracteres.¿La forma más rápida de encontrar cadena por subcadena en SQL?

Mi tarea consiste en obtener cadenas por una subcadena determinada. Las subcadenas también tienen longitud aleatoria y pueden ser inicio, mitad o final de las cadenas. La manera más obvia para llevarla a cabo:

SELECT * FROM t LIKE '%abc%' 

no me importa sobre INSERT, lo único que tiene que hacer selecciona rápidas. ¿Qué puedo hacer para realizar la búsqueda lo más rápido posible?

Uso MS SQL Server 2008 R2, la búsqueda de texto completo será inútil, hasta donde yo veo.

+11

Bienvenido al maravilloso mundo de rendimiento de la base de datos increíblemente pobre :-) – paxdiablo

+8

¿Por qué la búsqueda de texto completo será inútil? –

+0

¿podrían las subcadenas ser tokens? Si puedes dividir palabras por espacio, coma o guión, tengo una idea. Házmelo saber. – sgtz

Respuesta

8

Si desea utilizar menos espacio que la respuesta de Randy y hay una considerable repetición en sus datos, puede crear una estructura de árbol N-Ary donde cada borde es el siguiente carácter y colgar cada cadena y subcadena final en sus datos en eso.

Numere los nodos en profundidad de primer orden. Luego puede crear una tabla con hasta 255 filas para cada uno de sus registros, con el ID de su registro y el ID del nodo en su árbol que coincida con la cadena o la subcadena final. Luego, cuando realiza una búsqueda, encuentra el ID del nodo que representa la cadena que está buscando (y todas las subcadenas finales) y realiza una búsqueda de rango.

+0

Gracias, no puedo probar su solución y la de Randy en este momento, pero lo intentaré lo antes posible. – msergey

4

Parece que ha descartado todas las buenas alternativas.

Usted ya sabe que la consulta

SELECT * FROM t WHERE TITLE LIKE '%abc%' 

no va a usar un índice, que va a hacer una mesa de exploración completa cada vez.

Si estaban seguros de que la cadena estaba en el a partir del campo, que podría hacer

SELECT * FROM t WHERE TITLE LIKE 'abc%' 

que utilizaría un índice en el título.

¿Estás seguro de que la búsqueda de texto completo no te ayudaría aquí?

En función de sus necesidades de negocio, a veces he utilizado la siguiente lógica:

  • hacer un "comienza con" consulta (LIKE 'abc%') en primer lugar, que utilizará un índice.
  • Dependiendo de si se devuelven las filas (o cuántos), condicionalmente pasar a la búsqueda "más duro" que hará el análisis completo (LIKE '%abc%')

depende de lo que necesita, por supuesto, pero Lo he usado en situaciones en las que puedo mostrar los resultados más simples y más comunes primero, y solo paso a la consulta más difícil cuando sea necesario.

+0

Dada la subcadena más probable en el medio del título, pero trataré de medir el rendimiento con su enfoque. – msergey

+0

o un escaneo de índice agrupado. Probablemente no haya una gran diferencia. – JeffO

+0

@Jeff - Eso es solo semántica. Una exploración de índice agrupado es simplemente una "exploración de tabla completa" en una tabla que tiene un índice agrupado (que la mayoría de las tablas deberían tener de todos modos). De cualquier manera, tiene que leer cada registro. – BradC

13

si no te importa el almacenamiento, entonces puedes crear otra tabla con entradas de título parcial, comenzando con cada subcadena (hasta 255 entradas por título normal).

de esta manera, puede indexar estas subcadenas, y hacer coincidir solo con el comienzo de la cadena, debería mejorar en gran medida el rendimiento.

+1

convierte esa tabla en un índice agrupado no único ... que probablemente sea tan bueno como lo que obtendrá con SQL sin formato. – sgtz

3

Puede agregar otra columna calculada en la tabla: titleLength as len (título) PERSISTED. Esto almacenaría la longitud de la columna "título". Crea un índice sobre esto.

Además, agregue otra columna calculada llamada: ReverseTitle como Reverse (título) PERSISTED.

Ahora cuando alguien busca una palabra clave, verifique si la longitud de la palabra clave es la misma que la longitud del título. Si es así, haz una búsqueda "=". Si la longitud de la palabra clave es menor que la longitud de titleLength, haz un LIKE. Pero primero haz un título LIKE 'abc%', luego haz un reverseTitle LIKE 'cba%'. Similar al enfoque de Brad, es decir, usted hace la siguiente consulta difícil solo si es necesario.

Además, si las reglas 80-20 se aplican a sus palabras clave/subcadenas (es decir, si la mayoría de las búsquedas son en una minoría de las palabras clave), también puede considerar hacer algún tipo de almacenamiento en caché. Por ejemplo: supongamos que muchos usuarios buscan la palabra clave "abc" y esta búsqueda de palabra clave arroja registros con los identificadores 20, 22, 24, 25; puede almacenar esto en una tabla separada y hacer que este se indexe. Y ahora, cuando alguien busca una nueva palabra clave, primero mire en esta tabla de "caché" para ver si la búsqueda ya fue realizada por un usuario anterior. Si es así, no hay necesidad de volver a mirar en la tabla principal. Simplemente devuelve resultados de la tabla "caché".

También puede combinar lo anterior con SQL Server TextSearch. (suponiendo que tenga una razón válida para no usarlo). Sin embargo, podría utilizar Búsqueda de texto primero para preseleccionar el conjunto de resultados. y luego ejecute una consulta SQL en su tabla para obtener resultados exactos utilizando los Id devueltos por la búsqueda de texto como un parámetro junto con su palabra clave.

Todo esto es obviamente asumiendo que tiene que usar SQL. Si no, puedes explorar algo como Apache Solr.

0

Crear vista de índice hay una nueva característica en sql create index en la columna que necesita para buscar y usar esa vista después en su búsqueda que le dará un resultado más rápido.

0
  1. Uso ASCII charset con indexación agrupado columna de carbón. El juego de caracteres influye en el rendimiento de búsqueda debido al tamaño de los datos tanto en el disco RAM como en el disco. El cuello de botella a menudo es E/S.
  2. Su columna tiene 255 caracteres de largo por lo que puede usar el índice normal en su campo char en lugar de texto completo, que es más rápido. No seleccione columnas innecesarias en su instrucción seleccionada.
  3. Por último, agregue más RAM al servidor y aumente tamaño de caché.
+0

Encuentro el método del árbol N-Ary en otra respuesta hilarante. –

+2

¿Por qué es gracioso? –

0

Haga una cosa, utilice la clave principal en la columna específica & indexe en forma de agrupamiento.

Luego buscar usando cualquier (comodín o = o cualquier) método, buscará de manera óptima porque la tabla ya está en forma agrupada, por lo que sabe dónde puede encontrar (porque la columna ya está en forma ordenada)

Cuestiones relacionadas