SQL Server索引-对类似查询有何改进?

SQL Server索引-对类似查询有何改进?,sql,sql-server,select,Sql,Sql Server,Select,我们有一个查询,它运行在一个相当大的表上,不幸的是,该表需要在几个varchar字段上使用“%ABC%”,以便用户可以搜索部分名称等。SQL Server 2005 在使用LIKE时,在这些varchar字段上添加索引是否有助于提高select查询性能,或者在这些情况下,它基本上会忽略索引并进行完全扫描 只有在向这些列添加全文搜索并使用SQL Server的全文查询功能时,才能使用LIKE?提高性能的任何其他可能方法 否则,索引将不起作用。如“%ABC%”将始终执行完整表扫描。这是没有办法的 您

我们有一个查询,它运行在一个相当大的表上,不幸的是,该表需要在几个varchar字段上使用“%ABC%”,以便用户可以搜索部分名称等。SQL Server 2005

在使用LIKE时,在这些varchar字段上添加索引是否有助于提高select查询性能,或者在这些情况下,它基本上会忽略索引并进行完全扫描


只有在向这些列添加全文搜索并使用SQL Server的全文查询功能时,才能使用LIKE?

提高性能的任何其他可能方法


否则,索引将不起作用。

如“%ABC%”将始终执行完整表扫描。这是没有办法的

您确实有几种替代方法。首先是全文搜索,它是专门为这类问题设计的,所以我先来看一下

或者,在某些情况下,可以对数据进行非规范化,并将目标字段预处理为适当的标记,然后将这些可能的搜索项添加到单独的一对多搜索表中。例如,如果我的数据总是由一个包含模式“AAA/BBB/CCC”的字段组成,并且我的用户在BBB上搜索,那么我会在插入/更新时标记该字段(并在删除时删除)。这也是更倾向于使用触发器而不是应用程序代码的情况之一

我必须强调的是,这并不是一种真正的最佳技术,只有在数据与方法非常匹配并且出于某种原因您不想使用全文搜索的情况下才应该使用这种技术(并且类似扫描的数据库性能确实是不可接受的)。这也可能会使后续的维护工作头疼

唯一可以提高性能的方法(除了使用全文索引)是使用“LIKE ABC%”-不要在搜索词的两端添加通配符-在这种情况下,索引可以工作

如果您的要求是搜索词的两端都必须有通配符,那么您就不走运了


Marc

创建该列的统计信息。sql srever 2005优化了字符串内搜索,因此您可能会从中受益。

通过添加索引,您可能会看到性能的提高,这在很大程度上取决于细节:)

谓词列占行总大小的多少?您希望匹配多少行?您需要返回与谓词匹配的所有行,还是只返回前1行或前n行

如果您正在搜索具有高选择性/唯一性的值(返回的行太少),并且谓词列只占整个行大小的一小部分,那么索引可能非常有用。它仍然是一个扫描,但是您的索引每页可以容纳比源表更多的行

下面是一个示例,其中总行大小远大于要搜索的列大小:

create table t1 (v1 varchar(100), b1 varbinary(8000))
go
--add 10k rows of filler
insert t1 values ('abc123def', cast(replicate('a', 8000) as varbinary(8000)))
go 10000
--add 1 row to find
insert t1 values ('abc456def', cast(replicate('a', 8000) as varbinary(8000)))
go

set statistics io on 
go
select * from t1 where v1 like '%456%'
--shows 10001 logical reads

--create index that only contains the column(s) to search across
create index t1i1 on t1(v1)
go
select * from t1 where v1 like '%456%'
--or can force to 
--shows 37 logical reads
如果查看实际执行计划,您可以看到引擎扫描了索引,并在匹配行上进行了书签查找。或者,如果优化器没有决定单独使用此计划,您也可以直接告诉它使用索引: 使用(索引(t1i1))从t1中选择*其中v1类似于“%456%”

如果您有一组列要在几个高度选择性的列中搜索,那么您可以创建多个索引并使用缩减方法。例如,首先从高选择性索引中确定一组ID(或您的PK是什么),然后使用过滤器针对这一小组PK搜索您的低选择性列

如果您总是需要返回一大组行,那么使用表扫描几乎肯定会更好

因此,可能的优化在很大程度上取决于表定义的细节和数据的选择性

嗯!
-阿德里安

谢谢,这是我不幸的想法。我已经删除了一些类似的子句来帮助加快速度。如果在宽表中返回列的子集,也可以考虑包含索引。也考虑您正在查询的数据。例如,添加排除空字符串和/或空字符串的筛选索引,然后在查询中使用该索引将大大提高性能。索引将越来越小,然后就越来越少,以便同类扫描。这是否仅适用于像ABC%这样的
,还是同样适用于像%ABC
这样的
?另外,我很好奇为什么它只适用于单面通配符。。。你能详细解释一下吗?@TomPažourek:好吧,想象一下一本电话簿(如果你已经足够大了,记得那是什么:-);如果您正在搜索姓氏以
Smi
开头的人,您会很快找到
Smith
Smithers
等。但是,如果您搜索姓氏中包含(姓名中的任何位置)的人,例如
chuk
,拥有已排序的姓名列表(这就是索引的真正含义)对您没有多大帮助-您仍然需要滚动所有姓名以查找其姓名中包含该字符串的人谢谢:)您知道使用的是什么数据结构吗?它是某种形式的trie吗?这是否意味着
%ABC
将不使用任何索引?您只提到两端的通配符都不起作用。右端的通配符有效吗?