T-SQL 中是不是有 LIKE 语句的替代方法?

Posted

技术标签:

【中文标题】T-SQL 中是不是有 LIKE 语句的替代方法?【英文标题】:Is there and alternative to LIKE statement in T-SQL?T-SQL 中是否有 LIKE 语句的替代方法? 【发布时间】:2014-12-17 20:51:31 【问题描述】:

我有一个场景,我需要执行以下操作:

SELECT *
FROM
[dbo].[MyTable]
WHERE
[Url] LIKE '%<some url>%';

我必须在 Url ('%&lt;some url&gt;%') 的开头和结尾使用两个 %(通配符),因为即使他键入部分文本,用户也应该能够搜索完整的 url。例如,如果 url 是 http://www.google.co.in 并且用户键入“goo”,则 url 必须出现在搜索结果中。 LIKE 运算符导致性能问题。 我需要一个替代方案,这样我就可以摆脱这个语句和通配符。换句话说,我不想在这种情况下使用 LIKE 语句。我尝试使用 T-SQL CONTAINS,但它并没有解决我的问题。除了可以执行模式匹配并快速为我提供结果之外,还有其他替代方法吗?

【问题讨论】:

它以什么方式导致性能问题? 我已经简化了这个问题。请不要删除帖子。 您需要良好的索引。如果您在该列上没有正确的索引,则不同的运算符将无法帮助您。 @sharpcloud - 索引并没有那么大的帮助,因为它有一个前导通配符,它​​仍然需要扫描它。索引可以做的最好的事情是减少正在扫描的数据的宽度。 全文索引可能会有所帮助。 【参考方案1】:

以 % 开始点赞将导致扫描。没有绕过它。它必须评估每个值。

如果你索引列,它应该是索引(而不是表)扫描。

您没有不会导致扫描的替代方法。 Charindex 和 patindex 是替代品,但仍会扫描而不修复性能问题。

您能否将组件拆分为单独的表格? 万维网 谷歌 合作 在

然后像“goo%”这样搜索? 这将使用索引,因为它不以 % 开头。

更好的是,您可以在“google”上搜索并获得索引搜索。

并且您希望在该表中具有唯一的字符串,并在 Int PK 上单独连接,这样它就不会返回多个 www 例如。

Suspect FullText Contains 并没有更快,因为 FullText 将 URL 保留为一个单词。

【讨论】:

这如何回答“T-SQL 中的 LIKE 语句是否有替代方案?”的问题 @MartinSmith 但是没有其他方法可以纠正性能问题。 因此,如果这是您的答案,请将其放入答案中。目前,这绝不会回答 OP 的原始问题,即要求 LIKE 的替代方案而不是 LIKE 的解释。 @Blam 不,索引前导 % 将导致 index 扫描,这仍然比表扫描快。实际结果显然取决于他的具体情况。 并非如此。或:仅当大部分数据已过时且未使用时。否则,与仅表相比,我们将降低 RAM 速度并将表和索引保留在内存中。【参考方案2】:

您可以创建一个FULLTEXT 索引。

首先创建您的目录:

CREATE FULLTEXT CATALOG ft AS DEFAULT;

现在假设您的表名为 MyTable,列是 TextColumn,并且它有一个名为 UX_MyTable_TextColumn 的唯一索引:

CREATE FULLTEXT INDEX ON [dbo].[MyTable](TextColumn) 
    KEY INDEX UX_MyTable_TextColumn

现在您可以使用 CONTAINS 搜索表:

SELECT *
FROM MyTable
WHERE CONTAINS(TextColumn, 'searchterm')

【讨论】:

我刚试了下,还是不行。搜索“goo”不会产生“http://www.google.com”。搜索“google”可以,只要您搜索的是类似单词的内容,这会有所帮助。 搜索*goo*怎么样? 对我也不起作用。 “goo*”也没有。我应该立即承认我从未使用过全文索引,正是因为,一旦我阅读了它们,我就认为它们不能做我想做的事。 啊哈,成功了。如果我使用CONTAINS(TextColumn, '"goo*"'),它会返回一个命中——注意双引号。但是不要太热情——CONTAINS(TextColumn, '"*oogle*"') 仍然没有任何结果。我想说全文索引选项需要大量仔细测试。 FTS 包含只能使用尾随通配符。如果它不以goo 开头,则永远不会返回。除了坚持LIKE '%goo%'之外,似乎没有办法解决这个问题【参考方案3】:

据我所知,除了likecontains(全文搜索功能)之外,没有其他选择可以提供更好的性能。 您可以做的是尝试通过优化查询来提高性能。 为此,您需要了解您的用户以及他们将如何使用您的系统。 我怀疑大多数人会从地址的开头输入一个 URL(即没有协议),所以你可以这样做:

declare @searchTerm nvarchar(128) = 'goo'
set @searchTerm = coalesce(replace(@searchTerm ,'''',''''''),'')
select @searchTerm

SELECT *
FROM [dbo].[MyTable]
WHERE [Url] LIKE 'http://' + @searchTerm + '%'
or [Url] LIKE 'https://' + @searchTerm + '%'
or [Url] LIKE 'http://www.' + @searchTerm + '%'
or [Url] LIKE 'https://www.' + @searchTerm + '%'
or [Url] LIKE '%' + @searchTerm + '%'
option (fast 1); --get back the first result asap; 

这会给你一些优化;即如果 url 的 http://www.google.com 可以使用 url 列上的索引,因为 http://www.goo 位于字符串的开头。 结尾处的option (fast 1) 以确保看到此好处;由于最后一个URL like %searchTerm% 不能使用索引,我们宁愿尽快返回响应,而不是等待那个缓慢的部分完成。 想想其他常见的使用模式和解决方法。

【讨论】:

如果它可以工作,那将是相关的 - 遗憾的是,我认为优化器只会进行表扫描,因为它必须无论如何 - 而不是使用多个搜索路径,然后使用 tempdb 来摆脱双打。虽然需要测试,但我认为这是一个完全不起作用的技巧。例如,将协议删除(到单独的字段中)会起作用...... @TomTom 同意删除协议会更好——也许有第二个搜索列可以去除协议并将 nvarchar 转换为 varchar;仅将第二列用于搜索。更好的是上面的 Blam 解决方案;即解析 URL 并搜索其组成部分。【参考方案4】:

正如所写,您的查询无法进一步优化,也无法绕过LIKE 进行搜索。提高性能的唯一方法是减少 SELECT 以仅返回您不需要的所有列,并在 URL 上创建包含这些列的索引。 LIKE 将无法使用索引进行搜索,但减少扫描数据大小会有所帮助。如果您有支持压缩的 SQL Server 版本,那也会有所帮助。

例如,如果你真的只需要 A 列,那么写

SELECT A FROM [dbo].[MyTable] WHERE [Url] LIKE '%<some url>%';

并将索引创建为

CREATE INDEX IX_MyTable_URL 
ON MyTable([Url]) 
INCLUDE (A) WITH (DATA_COMPRESSION = PAGE);

如果 A 已经包含在您的主键中,则不需要 INCLUDE。

【讨论】:

【参考方案5】:

您的查询非常简单,我认为没有理由让它变慢。 dbms 将读取记录以获取记录并比较字符串。通常它甚至可以在并行线程中执行此操作。

您认为您的陈述如此缓慢的原因是什么?您的表中有数十亿条记录吗?您的记录包含这么多数据吗?

您最好的选择不是关心查询,而是关心数据库和您的系统。其他人已经建议在 url 列上建立索引,因此可以扫描索引而不是扫描表。最大并行度是否设置错误?你的桌子是碎片化的吗?你的硬件合适吗?这些是这里要考虑的事情。

但是:charindex('oogl', url) &gt; 0url like '%oogl%' 的作用相同,但在内部它们的工作方式有所不同。对于某些人来说,LIKE 表达式的结果更快,对于其他人来说,CHARINDEX 方法。也许这取决于查询、处理器数量、操作系统等等。可能值得一试。

【讨论】:

谢谢你们的回答。他们真的很有帮助。 :)

以上是关于T-SQL 中是不是有 LIKE 语句的替代方法?的主要内容,如果未能解决你的问题,请参考以下文章

存储过程

在T-SQL中具有可变数量的搜索条件的LIKE运算符

T-SQL 转义select …. like中的特殊字符(百分号)

在 T-SQl 中使用 like 搜索由未知数量的空格分隔的单词

mysql存储过程

在T-SQL中使用LIKE与存储过程完全匹配?