【问题标题】:SELECT Query speed varies heavily with different inputs?SELECT 查询速度因输入不同而有很大差异?
【发布时间】:2012-02-15 16:35:27
【问题描述】:

我的数据库中有这个存储过程:

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 人)。一般来说,当有很多可能的结果可供选择时,查询似乎运行得最快,而当要返回的结果很少时,查询运行得最慢。

如何加快查询速度?减慢对表的写入速度并不重要,但应用更多索引似乎无济于事。你有什么建议吗?

【问题讨论】:

  • 您是否尝试更新统计信息?在我将大量记录放入表后,我曾经遇到过与您的问题类似的问题。我认为统计信息的碎片不会正确更新,并且可能是 SQL 执行计划错误的原因。只是猜测
  • 这称为参数嗅探——本质上,SQL Server 会根据您传递的第一个参数来编译计划,虽然它可能会使用不同的参数做出不同的决定。您是否比较了执行计划的好坏?请参阅stackoverflow.com/questions/1007397/… 并获得我们的免费计划浏览器工具,它可以更好地突出这些问题sqlsentry.net/plan-explorer/sql-server-query-view.asp
  • @AaronBertrand 谢谢,我会得到你的软件,它看起来很有用。实际的存储过程有很多额外的参数(所有这些参数都可能为空),所以它设置了option(recompiled),我认为这意味着每次都重新编译一个计划。我已经编辑了我的问题以表明这一点。
  • @Pongsathon.keng 这就是小费,我将对此进行调查。表格的全部内容经常变化。

标签: sql sql-server-2005


【解决方案1】:

LIKE %something 上搜索将不会受益于 B 树索引。仅 4000 行搜索需要几秒钟(而不是几毫秒)的事实是这种情况的另一个提示。不要对查询计划中的 ClusteredIndexScan 感到困惑 - 这只是全表扫描的集群等效项。

那么,为什么会有差异?由于 accountantssoups 多得多,并且您只搜索 TOP N 行,因此第一个查询往往会比第二个查询更早地找到 N 行,即通过扫描表的较小部分。

您需要重写查询以使用LIKE something%,或者(如果可能)使用全文索引。

【讨论】:

  • 我之前没有使用过全文索引,我无法避免使用产生结果的东西作为LIKE %query%。对于这类查询,全文索引是否工作得很快?
  • @Oliver 全文索引适用于单词,而不适用于任意子字符串。所以不 - 这不会加速一般子字符串搜索,其中子字符串不一定落在单词边界上。但是如果您知道它总是会(落在单词边界上),您应该能够使用它来加快搜索速度(这就是我说“如果可能”的原因)。
  • @Oliver 再说一次,如果您可以将您的数据整齐地组织成“关键字”,您可以通过将关键字提取到单独的表格中来规范您的表格,然后您将能够搜索 = something 并使用普通的 B 树索引。
  • 我不能真正使用关键字,但我想我可以假设大多数子字符串都落在单词边界上,所以我会研究全文索引,谢谢。
猜你喜欢
  • 1970-01-01
  • 2019-10-02
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-12-08
  • 2010-10-27
相关资源
最近更新 更多