我有一个拥有(目前)3500万行的人名的数据库。我需要知道快速搜索这些名称的最佳方法是什么。当前的系统(不是我设计的),只是将索引的名字和姓氏列使用“LIKE”查询以及使用SOUNDEX的附加选项(虽然我不确定这实际上是用得多)。性能一直是该系统的一个问题,因此目前搜索限制为200个结果(运行时间仍然太长)。所以,我有几个问题:
仅供参考,我使用Fluent NHibernate进行数据访问,因此首选的方法将是首选。我目前正在使用SQL Server 2008。
编辑我想补充一点,我对处理常见拼写错误名称等问题的解决方案非常感兴趣,例如'smythe','smith',以及名字,例如' tomas','thomas'。
查询计划
|--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:
SELECT * FROM testdb.dbo.Test WHERE LastName LIKE 'WHITE%' AND FirstName LIKE 'THOMAS%'
根据Mitch的建议,我创建了一个这样的索引:
CREATE INDEX IX_Test_Name_DOB
ON Test (LastName ASC, FirstName ASC, BirthDate ASC)
INCLUDE (and here I list the other columns)
我的典型搜索(最后,第一次和出生日期)的搜索速度非常快。
答案 0 :(得分:5)
取决于您的LIKE查询的样子。
如果您正在搜索LIKE '%abc%'
,则无法使用索引,而在搜索LIKE 'abc%'
时,可以使用索引。此外,如果First和Last名称上的索引未“覆盖”发出的查询,则将执行密钥查找(书签查找)并显着影响性能。
您的索引是否定期重建?
您是否有示例查询计划?
更新:查询的覆盖索引是可用于执行WHERE条件的索引,还包含满足查询其余部分所需的所有列,例如SELECT列列表
Using Covering Indexes to Improve Query Performance
更新:即使您在(Lastname, Firstname)
上创建了一个复合索引(因为lastname应该更具选择性),查找所有其他列('*'列列表)仍然需要进入表聚集索引。
答案 1 :(得分:1)
我不喜欢soundex。我认为算法的更新迭代更好,但是你将英语中的每个单词都哈希到一个相当小的哈希值。随着时间的推移,这往往会产生大量的错误匹配。我已经阅读过metaphone并且它的后继双音素电话更好,但我没有直接经验。
米奇对like
的报道非常透彻,所以我不打算再重复一遍。
答案 2 :(得分:0)
如果您在名字和姓氏列上创建索引,那么使用LIKE的完全匹配搜索和前缀搜索将变得非常快。
(在MySQL中,“如果LIKE的参数是一个不以通配符开头的常量字符串,索引也可以用于LIKE比较。”我认为MS SQL有一个类似的规则,但是检查MS SQL文档以确定。)
要加速SoundEx搜索,请存储名字和姓氏新列的SoundEx版本,并在这些列上创建索引。