5

Tengo una base de datos de nombres de personas que tiene (actualmente) 35 millones de filas. Necesito saber cuál es el mejor método para buscar rápidamente estos nombres. El sistema actual (no diseñado por mí) simplemente tiene indexadas las columnas del nombre y apellido y utiliza consultas "LIKE" con la opción adicional de usar SOUNDEX (aunque no estoy seguro de que esto realmente se use mucho). El rendimiento siempre ha sido un problema con este sistema, por lo que actualmente las búsquedas están limitadas a 200 resultados (lo que aún tarda demasiado en ejecutarse). Entonces, tengo algunas preguntas:SQL Server Search Nombres adecuados Índice de texto completo vs LIKE + SOUNDEX

  1. ¿El índice de texto completo funciona bien para los nombres propios?
  2. Si es así, ¿cuál es la mejor manera de consultar los nombres propios? (CONTIENE, FREETEXT, etc.)
  3. ¿Hay algún otro sistema (como Lucene.net) que sería mejor?

Solo como referencia, estoy usando Fluent NHibernate para acceso a datos, por lo que los métodos que funcionan serán preferidos. Estoy usando SQL Server 2008 actualmente.

EDITAR Quiero añadir que estoy muy interesado en soluciones que lidiar con cosas como nombres mal escritas habitualmente, por ejemplo, los nombres de pila 'smythe', 'Smith', así como, por ejemplo, 'Tomas', ' thomas '.

plan de consulta

|--Parallelism(Gather Streams) 
     |--Nested Loops(Inner Join, OUTER REFERENCES:([testdb].[dbo].[Test].[Id], [Expr1004]) OPTIMIZED WITH UNORDERED PREFETCH) 
      |--Hash Match(Inner Join, HASH:([testdb].[dbo].[Test].[Id])=([testdb].[dbo].[Test].[Id])) 
      | |--Bitmap(HASH:([testdb].[dbo].[Test].[Id]), DEFINE:([Bitmap1003])) 
      | | |--Parallelism(Repartition Streams, Hash Partitioning, PARTITION COLUMNS:([testdb].[dbo].[Test].[Id])) 
      | |   |--Index Seek(OBJECT:([testdb].[dbo].[Test].[IX_Test_LastName]), SEEK:([testdb].[dbo].[Test].[LastName] >= 'WHITDþ' AND [testdb].[dbo].[Test].[LastName] < 'WHITF'), WHERE:([testdb].[dbo].[Test].[LastName] like 'WHITE%') ORDERED FORWARD) 
      | |--Parallelism(Repartition Streams, Hash Partitioning, PARTITION COLUMNS:([testdb].[dbo].[Test].[Id])) 
      |   |--Index Seek(OBJECT:([testdb].[dbo].[Test].[IX_Test_FirstName]), SEEK:([testdb].[dbo].[Test].[FirstName] >= 'THOMARþ' AND [testdb].[dbo].[Test].[FirstName] < 'THOMAT'), WHERE:([testdb].[dbo].[Test].[FirstName] like 'THOMAS%' AND PROBE([Bitmap1003],[testdb].[dbo].[Test].[Id],N'[IN ROW]')) ORDERED FORWARD) 
      |--Clustered Index Seek(OBJECT:([testdb].[dbo].[Test].[PK__TEST__3214EC073B95D2F1]), SEEK:([testdb].[dbo].[Test].[Id]=[testdb].[dbo].[Test].[Id]) LOOKUP ORDERED FORWARD) 

SQL para arriba:

SELECT * FROM testdb.dbo.Test WHERE LastName LIKE 'WHITE%' AND FirstName LIKE 'THOMAS%' 

según el consejo del Mitch, que crea un índice de esta manera:

CREATE INDEX IX_Test_Name_DOB 
ON Test (LastName ASC, FirstName ASC, BirthDate ASC) 
INCLUDE (and here I list the other columns) 

Mis búsquedas son ahora increíblemente rápido para mi búsqueda típica (última, primera y fecha de nacimiento).

+0

¿También puede publicar el TSQL por favor? –

Respuesta

5

Depende de lo que parecen sus consultas LIKE.

Si está buscando LIKE '%abc%', entonces no se puede utilizar ningún índice, mientras que al buscar LIKE 'abc%' se puede usar un índice. Además, si el (los) índice (s) en el nombre y apellido no están 'cubriendo' la consulta emitida, entonces se realizarán búsquedas de claves (búsquedas de marcadores) y afectarán significativamente el rendimiento.

¿Sus índices se reconstruyen regularmente?

¿Tiene un plan de consulta de ejemplo?

Actualización: Un índice de cobertura para una consulta es aquel que se puede utilizar para realizar los criterios WHERE y también tiene todas las columnas necesarias para satisfacer el resto de la consulta, como la lista de columnas SELECCIONAR.

Using Covering Indexes to Improve Query Performance

actualización: Incluso si se crea un índice compuesto en (Lastname, Firstname) (desde apellido debería ser más selectivos), seguirá siendo necesaria una búsqueda por todas las otras columnas (la lista '*' columna) en las tablas índice agrupado.

+0

Los índices se reconstruirán periódicamente, probablemente semanalmente. Estoy agregando registros a razón de aproximadamente 5,000 por día. Ha, parece que el sistema actual no está usando "LIKE" en absoluto, evidentemente demasiado lento. Entonces, diría que 'abc%' debería ser una mejora. –

+0

¿Qué quiere decir con "cobertura"? –

+0

Esto es realmente útil, Mitch. Estoy trabajando para obtener un plan de consulta de ejemplo para usted. Entonces, ¿debería crear un único índice que contenga todas las columnas que me interesan? –

0

Si crea un índice en las columnas del nombre y apellido, entonces las búsquedas de coincidencia exacta y las búsquedas de prefijo usando LIKE se volverán increíblemente rápidas.

, "MySQL," El índice también se puede usar para las comparaciones LIKE si el argumento para LIKE es una cadena constante que no comienza con un carácter comodín. "Creo que MS SQL tiene una regla similar, pero revisa la MS Documentación SQL para estar seguro.)

Para acelerar las búsquedas SoundEx, almacene la versión SoundEx del nombre y apellido de las nuevas columnas y cree índices en esas columnas.

1

No me gusta mucho el soundex. Creo que las iteraciones más recientes del algoritmo son mejores, pero estás mezclando cada palabra en el idioma inglés con un hash bastante pequeño. Esto tiende a generar una tonelada de coincidencias falsas con el tiempo. He leído que el metafonía y su sucesor doble metafonía son mejores, pero no tengo experiencia directa con ellos.

La cobertura de Mitch de like es bastante minuciosa, así que no voy a repetirla.

+0

Gracias por la información en soundex. –

Cuestiones relacionadas