【问题标题】:Best way to index a SQL table to find best matching string索引 SQL 表以查找最佳匹配字符串的最佳方法
【发布时间】:2016-11-01 23:21:23
【问题描述】:

假设我有一个带有int PK 列和nvarchar(max) 的SQL 表。在nvarchar(max) 列中,我有一堆表格条目,都是这样的:

SOME_PEOPLE_LIKE_APPLES
SOME_PEOPLE_LIKE_APPLES_ON_TUESDAY
SOME_PEOPLE_LIKE_APPLES_ON_THE_MOON
SOME_PEOPLE_LIKE_APPLES_ON_THE_MOON_CAFE
SOME_PEOPLE_LIKE_APPLES_ON_THE_RIVER
.
.
.
SOME_ANTS_HATE_SYRUP
SOME_ANTS_HATE_SYRUP_WITH_STRAWBERRIES

有数百万行 - 那么假设我的目标是找到与输入 searchTerm 重叠最多的行 - 所以在这种情况下,如果我输入 SOME PEOPLE_LIKE_APPLES_ON_THE_MOON_MOUNTAIN,则返回的条目将是第三个条目从上表来看,SOME_PEOPLE_LIKE_APPLES_ON_THE_MOON

我有一个非常天真的 SPROC,它遍历整个表如下:

SELECT DISTINCT phrase, len(phrase) l, [id] FROM X WHERE searchTerm LIKE phrase + '%'

-- phrase is the row entry being searched against
-- searchTerm is the phrase we're searching for

然后我将ORDER BY 长度并仅选择TOP

有没有办法加快这个速度,也许通过做一些索引?

如果这令人困惑,请将其视为tableRowEntry + wildcard = searchTerm

如果这有什么不同的话,我正在使用 MSSQL 2008

【问题讨论】:

  • 您的查询应该使用searchTerm 上的索引,假设phrase 确实是一个常量参数。
  • 马特,看看我的更新示例......

标签: sql sql-server indexing


【解决方案1】:

如果您的 NVARCHAR 列上有索引,LIKE 'Something%' -search 将能够使用它并且应该很快。

如果开头有通配符,那你就不走运了。但是 - 在你的情况下 - 这应该有效。

您可以使用索引的持久计算列来存储字符串的长度。在这种情况下,您可以通过过滤掉所有过短或过长的字符串来极大地减少工作量。

如果您的搜索词中有某些词经常出现但并非无处不在,您可能会再次使用侧栏并像AND InlcudePEOPLE=1 AND IncludeMOON=1这样进行过滤

更新

这是一个例子

CREATE TABLE Phrase(ID INT IDENTITY
                   ,Phrase NVARCHAR(100)
                   ,PhraseLength AS LEN(Phrase) PERSISTED);
CREATE INDEX IX_Phrase_Phrase ON Phrase(Phrase);
CREATE INDEX IX_Phrase_PhraseLength ON Phrase(PhraseLength);

INSERT INTO Phrase
VALUES
 ('SOME_PEOPLE_LIKE_APPLES')
,('SOME_PEOPLE_LIKE_APPLES_ON_TUESDAY')
,('SOME_PEOPLE_LIKE_APPLES_ON_THE_MOON')
,('SOME_PEOPLE_LIKE_APPLES_ON_THE_MOON_CAFE')
,('SOME_PEOPLE_LIKE_APPLES_ON_THE_RIVER')
,('SOME_ANTS_HATE_SYRUP')
,('SOME_ANTS_HATE_SYRUP_WITH_STRAWBERRIES');

DECLARE @SearchTerm NVARCHAR(100)=N'SOME_PEOPLE_LIKE_APPLES_ON_THE_MOON_MOUNTAIN';

--这使用索引(检查执行计划)

SELECT TOP 1 * 
FROM Phrase 
WHERE @SearchTerm LIKE Phrase + '%'
ORDER BY PhraseLength DESC;

--这可能会更好,请检查您的高行数。

SELECT TOP 1 *
FROM Phrase
WHERE Phrase=LEFT(@SearchTerm,PhraseLength)
ORDER BY PhraseLength DESC;
GO

--清理

DROP TABLE Phrase;

【讨论】:

  • 恕我直言,OP 无法真正过滤出太长和太短的结果,因为他正在寻找最接近的匹配项。如果最接近的匹配在长度方面不是完全匹配怎么办?
  • @KamilG。好吧,有必要定义 closest ...应该整理出很长的字符串-至少我是这样理解的...
  • 我相信一个边缘情况是当搜索词只有一个匹配并且它与搜索短语的长度距离很大,但它仍然应该考虑它。例如:搜索短语 len = 10,只找到一个匹配 len = 1000。
  • @KamilG。我只是添加了一些示例(没有长度检查,这可能会另外完成,具体取决于实际的业务案例)
  • 谢谢,我理解你之前的观点。对我没有吸引力的事情是在应用限制之前过滤掉 - 我相信有很多情况下您无法指定。
【解决方案2】:

这里最好的解决方案是创建全文搜索索引:

https://msdn.microsoft.com/en-us/library/ms142571.aspx

全文搜索已针对此任务进行了优化,创建索引后,您可以使用带有 CONTAINS 全文功能的全文查询来有效地查找匹配项:

SELECT DISTINCT phrase, len(phrase) l, [id] FROM X WHERE CONTAINS(phrase, searchPhrase)

全文搜索不仅允许通过 OPTIMIZE FOR 等查询提示进行自定义优化,还允许在搜索词中使用 AND 和 OR 等停用词,以及各种其他文本搜索功能,例如能够找到拼写变体自动搜索同一个词并按相关性等进行过滤。

【讨论】:

    猜你喜欢
    • 2016-07-01
    • 1970-01-01
    • 2015-10-03
    • 1970-01-01
    • 2013-11-26
    • 1970-01-01
    • 1970-01-01
    • 2014-08-26
    • 2015-10-25
    相关资源
    最近更新 更多