SQL Server搜索正确命名全文索引与LIKE + SOUNDEX

时间:2010-06-01 01:02:49

标签: sql-server fluent-nhibernate full-text-search lucene.net

我有一个拥有(目前)3500万行的人名的数据库。我需要知道快速搜索这些名称的最佳方法是什么。当前的系统(不是我设计的),只是将索引的名字和姓氏列使用“LIKE”查询以及使用SOUNDEX的附加选项(虽然我不确定这实际上是用得多)。性能一直是该系统的一个问题,因此目前搜索限制为200个结果(运行时间仍然太长)。所以,我有几个问题:

  1. 全文索引是否适用于专有名称?
  2. 如果是这样,查询专有名称的最佳方法是什么? (CONTAINS,FREETEXT等)
  3. 是否有其他系统(如Lucene.net)更好?
  4. 仅供参考,我使用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)
    

    我的典型搜索(最后,第一次和出生日期)的搜索速度非常快。

3 个答案:

答案 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版本,并在这些列上创建索引。