Warning: file_get_contents(/data/phpspider/zhask/data//catemap/5/sql/68.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
索引SQL表以查找最佳匹配字符串的最佳方法_Sql_Sql Server_Indexing - Fatal编程技术网

索引SQL表以查找最佳匹配字符串的最佳方法

索引SQL表以查找最佳匹配字符串的最佳方法,sql,sql-server,indexing,Sql,Sql Server,Indexing,假设我有一个SQL表,它有一个intPK列和一个nvarchar(max)。在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 . . .

假设我有一个SQL表,它有一个
int
PK列和一个
nvarchar(max)
。在
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
-因此在这种情况下,如果我输入
一些人喜欢月亮山上的苹果
,返回的条目将是上表中的第三个条目,
一些人喜欢月亮上的苹果

我有一个非常天真的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
然后我按长度排序,只选择顶部

有没有一种方法可以加速这个过程,也许是通过建立索引

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


我在MSSQL 2008上,如果这有什么不同的话

如果你的NVARCHAR列a
上有一个像'Something%'这样的索引
-搜索将能够使用它,而且应该非常快

如果一开始有一个通配符,你就不走运了。但是,在你的情况下,这应该是可行的

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

如果搜索词中有某些词经常出现,但并非无处不在,则可以再次使用边栏并进行筛选,如
和inlcudepople=1和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 Phrase=LEFT(@SearchTerm,PhraseLength)
ORDER BY PhraseLength DESC;
GO
--清理


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

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

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

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

你的查询应该使用
searchTerm
上的索引,假设
phrase
确实是一个常量参数。Matt,请参见我的更新示例…IMHO,OP无法筛选太长或太短的结果,因为他正在寻找最接近的匹配项。如果最接近的匹配在长度上不是完全匹配怎么办?@KamilG。嗯,有必要定义最近的。。。应该对过长的字符串进行分类——至少我是这样理解的……我相信当搜索词只有一个匹配项,并且它的长度与搜索短语的距离很大时,会出现边缘情况,但它仍然应该考虑到这一点。例如:搜索短语len=10,只找到一个len=1000的匹配项。@KamilG。我刚刚添加了一些示例(没有长度检查,这可能需要额外完成,具体取决于实际的业务案例)。谢谢,我理解了您之前的观点。一些对我不感兴趣的事情是在应用限制之前过滤掉——我相信有很多情况下你不能指定。
DROP TABLE Phrase;
SELECT DISTINCT phrase, len(phrase) l, [id] FROM X WHERE CONTAINS(phrase, searchPhrase)