我有一些列EntityName,我希望用户能够通过输入以空格分隔的单词来搜索名称。该空间被隐式地视为“AND”运算符,这意味着返回的行必须具有指定的所有单词,并且不一定按给定顺序。
例如,如果我们有这样的行:
当用户输入:me you
或you me
(结果必须相同)时,结果包含第2行和第3行。
我知道我可以这样:
WHERE Col1 LIKE '%' + word1 + '%'
AND Col1 LIKE '%' + word2 + '%'
但我想知道是否有更优化的解决方案。
CONTAINS
需要一个全文索引,由于各种原因,它不是一个选项。
对于这些案例,也许Sql2008有一些内置的,半隐藏的解决方案?
答案 0 :(得分:3)
我唯一能想到的就是编写CLR
函数进行LIKE
比较。这应该快很多倍。
更新:现在我考虑一下,CLR无济于事。另外两个想法:
1 - 尝试索引Col1并执行此操作:
WHERE (Col1 LIKE word1 + '%' or Col1 LIKE '%' + word1 + '%')
AND (Col1 LIKE word2 + '%' or Col1 LIKE '%' + word2 + '%')
根据最常见的搜索(以子字符串开头),这可能会有所改进。
2 - 添加您自己的全文索引表,其中每个单词都是表格中的一行。然后你可以正确索引。
答案 1 :(得分:3)
CREATE FUNCTION [dbo].[fnSplit] ( @sep CHAR(1), @str VARCHAR(512) )
RETURNS TABLE AS
RETURN (
WITH Pieces(pn, start, stop) AS (
SELECT 1, 1, CHARINDEX(@sep, @str)
UNION ALL
SELECT pn + 1, stop + 1, CHARINDEX(@sep, @str, stop + 1)
FROM Pieces
WHERE stop > 0
)
SELECT
pn AS Id,
SUBSTRING(@str, start, CASE WHEN stop > 0 THEN stop - start ELSE 512 END) AS Data
FROM
Pieces
)
DECLARE @FilterTable TABLE (Data VARCHAR(512))
INSERT INTO @FilterTable (Data)
SELECT DISTINCT S.Data
FROM fnSplit(' ', 'word1 word2 word3') S -- Contains words
SELECT DISTINCT
T.*
FROM
MyTable T
INNER JOIN @FilterTable F1 ON T.Col1 LIKE '%' + F1.Data + '%'
LEFT JOIN @FilterTable F2 ON T.Col1 NOT LIKE '%' + F2.Data + '%'
WHERE
F2.Data IS NULL
答案 2 :(得分:2)
答案 3 :(得分:2)
无论如何,你最终会得到全表扫描。
整理可以显然有很大的不同。 Kalen Delaney在书“Microsoft SQL Server 2008 Internals”中说:
整理可以产生巨大的差异 什么时候SQL Server几乎要看 字符串中的所有字符。对于 例如,请看以下内容:SELECT COUNT(*) FROM tbl WHERE longcol LIKE '%abc%'
使用二进制排序规则可以比非二进制Windows排序规则快10倍或更多。使用
varchar
数据时,SQL排序规则的执行速度比Windows排序规则快7到8倍。
答案 4 :(得分:1)
WITH Tokens AS(SELECT 'you' AS Token UNION ALL SELECT 'me')
SELECT ...
FROM YourTable AS t
WHERE (SELECT COUNT(*) FROM Tokens WHERE y.Col1 LIKE '%'+Tokens.Token+'%')
=
(SELECT COUNT(*) FROM Tokens) ;
答案 5 :(得分:0)
理想情况下,这应该在如上所述的全文搜索的帮助下完成。 但, 如果您没有为数据库配置全文本,则这是一种性能密集型解决方案,用于进行优先的字符串搜索。
{{1}}