我在我的数据库中有这个存储过程:
ALTER PROCEDURE [dbo].[sp_FTSearchLocation]
@SearchFor nvarchar(200) = null
,@StartRow int
,@EndRow int
AS
BEGIN
SET NOCOUNT ON;
SELECT * FROM (
SELECT TOP (@EndRow)
*, ROW_NUMBER() OVER (ORDER BY Recommendations DESC, CompanyName) AS num
FROM
dbo.cachedSearchTable
WHERE
(
(@SearchFor IS NULL)
OR (CompanyName like '%' + @SearchFor + '%')
OR (Handle like '%' + @SearchFor + '%')
OR (Activity like '%' + @SearchFor + '%')
)
) As a
WHERE num > @StartRow
OPTION (RECOMPILE)
END
dbo.cachedSearchTable
有一个聚簇索引,其列为Recommendations DESC, CompanyName
。没有其他索引。我认为使用*
是安全的,因为表cachedSearchTable
被构造为只包含与此查询相关的列。
对于某些搜索字符串,此过程运行速度非常快。例如,在不到一秒的时间内搜索accountants
返回。但是,其他人的运行速度非常慢:当@SearchFor
设置为soup
时,返回时间约为6秒。
每个的执行计划看起来都是一样的:
Accountants
:
ClusteredIndexScan (85%) ->
Segment (15%) ->
ComputeScalar (0%) ->
SequenceProject (0%) ->
Top (0%) ->
Filter (0%) ->
Select (0%).
Soup
:
ClusteredIndexScan (95%) ->
Parallelism (Gather Streams) (5%) ->
Segment (0%) ->
ComputeScalar (0%) ->
SequenceProject (0%) ->
Top (0%) ->
Filter (0%) ->
Select (0%).
但是,对于accountants
,ClusteredIndexScan的运营商成本估计为0.57,而对于soup
,其成本为25.34。
我尝试在表上放置3个非聚集索引 - 每个搜索列一个 - 但这没有帮助。
我的数据库中有很多会计师(~4000),而且他们名字中的'汤'很少(~50)。一般来说,当有很多可能的结果可供选择时,查询似乎运行得最快,而当返回的结果很少时,查询运行速度最慢。
如何加快此查询?降低写入表的速度并不重要,但应用更多索引似乎没有帮助。你能提出什么建议吗?
答案 0 :(得分:3)
在LIKE %something
上搜索不会从B树索引中受益。事实上只有4000行需要几秒钟(而不是毫秒)才能进行搜索,这是一个额外的提示。不要被查询计划中的ClusteredIndexScan弄糊涂 - 这只是全表扫描的集群等价物。
那么,为什么差异呢?由于还有更多accountants
然后soup
s,并且您只搜索TOP N行,第一个查询将倾向于比第二个查找更早的N行,即通过扫描较小的部分该表。
您需要重写查询才能使用LIKE something%
,或者(如果可能)使用全文索引。