【问题标题】:Query so much slower than stored procedure?查询比存储过程慢很多?
【发布时间】:2012-11-22 20:05:50
【问题描述】:

我创建了一个查询,它在前 100 名中执行大约 2 秒。如果我创建这个确切查询的存储过程,它需要 12-13 秒才能运行。

为什么会这样?

  • 元素表计数 = 2309015(指定用户 ID = 326969)
  • 匹配表数 = 1290(指定用户 ID = 498)
  • 站点表计数 = 71(指定用户 ID = 9)

代码

 with search (elementid, siteid, title, description, site, link, addeddate)
 as
 (
     select top(@top) 
         elementid,
         elements.siteid, title, elements.description,
         site =
             case sites.description
                 when '' then sites.name
                 when null then sites.name
                 else sites.name + ' (' + sites.description + ')'
             end, 
        elements.link,
        elements.addeddate 
    from elements
        left join sites on elements.siteid = sites.siteid
    where title like @search and sites.userid = @userid
    order by addeddate desc
)
select search.*, isnull(matches.elementid,0) as ismatch 
from search
    left join matches on matches.elementid = search.elementid

【问题讨论】:

  • 你看过查询执行计划吗?
  • “我创建了一个查询,它在前 100 名中执行大约 2 秒。如果我创建这个精确查询的存储过程,它需要 12-13 秒才能运行”。因此,存储的过程比查询慢得多。
  • @HamletHakobyan 我不明白,sp 很慢是的...(现在查看执行计划)
  • 有一个成本,它是为 elementid 指定的元素表上的聚集索引。似乎是因为内部连接....但这并不能解释为什么在存储过程中运行时它的速度如此之慢...
  • 您有一些关于为什么它变慢以及如何避免这种情况的答案,请接受其中一个答案或取消删除您自己的答案并接受它。还是您需要更多答案?

标签: sql-server sql-server-2008 stored-procedures view


【解决方案1】:

当你创建 SP 时,它被编译和存储,当 SP 有参数时,你过滤你的结果,优化器不知道你将在执行时传递哪个值,然后他将其视为 33% 选择并由此创建计划。当您执行查询时,会提供这些值,优化器会根据这些值创建执行计划。我确定,计划不同。

【讨论】:

    【解决方案2】:

    没有代码,我只能猜测。编写示例查询时,首先有一个常量 where 子句,其次有一个缓存。存储过程没有机会根据 where 子句中的常量缓存或优化查询计划。

    【讨论】:

    • 我不明白为什么会有差异。运行存储过程时,我像这样运行它:exec web_storedprocedure 1, 100, '%searchphrase%'。这是一个很慢的存储过程,它没有缓存任何东西......如果查询是那个很慢的,我会理解的......
    【解决方案3】:

    我可以建议两种方法来尝试

    第一个,这样写​​你的sp:

    create procedure sp_search
    (
        @top int,
        @search nvarchar(max),
        @userid int
    )
    as
    begin
        declare @p_top int, @p_search nvarchar(max), @p_userid int
    
        select @p_top = @top, @p_search = @search, @p_userid = @userid
    
        with search (elementid, siteid, title, description, site, link, addeddate)
        as
        (
            select top(@p_top) 
                elementid,
                elements.siteid, title, elements.description,
                site =
                 case sites.description
                     when '' then sites.name
                     when null then sites.name
                     else sites.name + ' (' + sites.description + ')'
                 end, 
                elements.link,
                elements.addeddate 
            from elements
                left join sites on elements.siteid = sites.siteid
            where title like @p_search and sites.userid = @p_userid
            order by addeddate desc
        )
        select search.*, isnull(matches.elementid,0) as ismatch 
        from search
            left join matches on matches.elementid = search.elementid
    end
    

    二、使用内联表函数

    create function sf_search
    (
        @top int,
        @search nvarchar(max),
        @userid int
    )
    returns table
    as
    return
    (
        with search (elementid, siteid, title, description, site, link, addeddate)
        as
        (
            select top(@top) 
                elementid,
                elements.siteid, title, elements.description,
                site =
                 case sites.description
                     when '' then sites.name
                     when null then sites.name
                     else sites.name + ' (' + sites.description + ')'
                 end, 
                elements.link,
                elements.addeddate 
            from elements
                left join sites on elements.siteid = sites.siteid
            where title like @search and sites.userid = @userid
            order by addeddate desc
        )
        select search.*, isnull(matches.elementid,0) as ismatch 
        from search
            left join matches on matches.elementid = search.elementid
    )
    

    【讨论】:

    • 我不认为参数嗅探通常被建议?我已经读过这样做的许多缺点(与您发布的 sp 相关)
    【解决方案4】:

    有一个类似的问题here

    问题是存储过程声明SET ANSI_NULLS OFF

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2015-02-23
      • 1970-01-01
      • 1970-01-01
      • 2013-12-07
      • 2013-06-10
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多