5 回答
使用全文索引而不是 LIKE。
创建全文索引:
http://msdn.microsoft.com/en-us/library/ms187317.aspx
CREATE UNIQUE INDEX ix1 ON tbl_MyTable(YourKey); //unique index required
CREATE FULLTEXT CATALOG ft AS DEFAULT; // ft is your freetext catalog name
CREATE FULLTEXT INDEX ON tbl_MyTable(Name)
KEY INDEX ix1
WITH STOPLIST = SYSTEM; // this is your index and allows you to run the command below
然后使用它来运行您的查询:
SELECT Name
FROM tbl_MyTable
WHERE FREETEXT(Name, 'dont');
对于这种事情,这是最快的技术。如果您使用第三方自由文本引擎,您可以获得更快的速度,但可能没有必要这样做。
我建议创建一个用户定义的函数来巩固这个逻辑:
CREATE FUNCTION [dbo].[udf_StripQuotes]
(
@String VARCHAR(MAX)
)
RETURNS VARCHAR(MAX)
AS
BEGIN
RETURN Replace(
Replace(
Replace(
Replace(
Replace(
Replace(@String,'“',''),
'‘',''),
'''',''),
'"',''),
'’',''),
'”','')
END
GO
然后看起来像:
select Name
from tbl_MyTable
where dbo.udf_StripQuotes(name) like '% dont%';
就效率而言,语句%
中的前导和尾随like
将阻止您使用任何索引,这将导致全表扫描......这可能是此查询的最大性能损失。
但是,正如 Aaron 所阐明的那样,由于调用 UDF 的开销,此实现将比原始实现慢。
如果您可以避免使用前导通配符,那么带有索引的计算列可能会提高性能。
否则,我认为您唯一的其他选择是实施Full-Text Search。
这不是问题的答案,但很难作为评论来实施。
如果您打算使用 UDF 来简化查询本身,请帮自己一个忙,并将函数调用限制为您拥有的行数,而不是加倍。代替:
where dbo.udf_StripQuotes(name) like 'dont%'
or dbo.udf_StripQuotes(name) like '% dont%' );
做这个:
where ' ' + dbo.udf_StripQuotes(name) like '% dont%';
就根本问题而言,我同意 Michael 的观点,即索引计算列可能是最好的,但如果 name 列超过 900 个字节,这将是不可能的(并且这不会神奇地将扫描转换为搜索,因为通配符,它只是消除了调用函数或在查询中执行所有这些替换调用的需要)。
空间效率还是时间效率?
您的第一个解决方案是节省空间的,但由于每次执行查询时将多个字符串函数应用于表中的每一行,因此可能效率低下。
生成列的解决方案空间效率低,但由于应用字符串操作一次(当您添加列然后在插入/更新时),可能会节省时间。
从您的用户的角度来看,最好的解决方案可能是在生成的列上执行搜索。
尝试以下操作以返回所有名称,不带任何引号或双引号。这将避免 LIKE 语句的必要性,避免另一列的必要性,并加快您的查询:
SELECT Replace(
Replace(
Replace(
Replace(
Replace(
Replace( Name, '“', ''),
'‘', ''),
'''',''),
'"', ''),
'’',''),
'”', '') AS Name
FROM tbl_MyTable