Warning: file_get_contents(/data/phpspider/zhask/data//catemap/0/performance/5.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Sql server 改进报告存储过程执行时间-调整临时表?_Sql Server_Performance_Stored Procedures_Sql Server 2008 R2 - Fatal编程技术网

Sql server 改进报告存储过程执行时间-调整临时表?

Sql server 改进报告存储过程执行时间-调整临时表?,sql-server,performance,stored-procedures,sql-server-2008-r2,Sql Server,Performance,Stored Procedures,Sql Server 2008 R2,我的任务是提高由SSRS前端调用的报告存储过程的性能(这是我第一次在现实世界中进行性能调优),该存储过程目前在最大数据量(基于从报告前端设置的过滤器)上运行大约需要30秒 此存储过程中执行了19个查询,其中大多数查询将数据从基表内部的初始(遗留)格式转换为有意义的数据集,以显示给业务端 我基于几个DMV创建了一个查询,以找出存储过程中哪些是最消耗资源的查询(下面是一个小片段),我找到了一个平均需要10秒才能完成的查询 select object_name(st.objectid)

我的任务是提高由SSRS前端调用的报告存储过程的性能(这是我第一次在现实世界中进行性能调优),该存储过程目前在最大数据量(基于从报告前端设置的过滤器)上运行大约需要30秒

此存储过程中执行了19个查询,其中大多数查询将数据从基表内部的初始(遗留)格式转换为有意义的数据集,以显示给业务端

我基于几个DMV创建了一个查询,以找出存储过程中哪些是最消耗资源的查询(下面是一个小片段),我找到了一个平均需要10秒才能完成的查询

select
    object_name(st.objectid)                                                                    [Procedure Name]
    , dense_rank() over (partition by st.objectid order by qs.last_elapsed_time desc)           [rank-execution time]
    , dense_rank() over (partition by st.objectid order by qs.last_logical_reads desc)          [rank-logical reads]
    , dense_rank() over (partition by st.objectid order by qs.last_worker_time desc)            [rank-worker (CPU) time]
    , dense_rank() over (partition by st.objectid order by qs.last_logical_writes desc)         [rank-logical write]
        ...
from sys.dm_exec_query_stats as qs
    cross apply sys.dm_exec_sql_text (qs.sql_handle) as st
    cross apply sys.dm_exec_text_query_plan (qs.plan_handle, qs.statement_start_offset, qs.statement_end_offset) as qp
where st.objectid in ( object_id('SuperDooperReportingProcedure') )
    , [rank-execution time]
    , [rank-logical reads]
    , [rank-worker (CPU) time]
    , [rank-logical write] desc
现在,这个查询有点奇怪,因为执行计划显示,大部分工作(~80%)是在将数据插入本地临时表时完成的,而不是在查询从中获取源数据并进行操作的其他表时完成的。(下面的屏幕截图来自SQL Sentry Plan Explorer)

此外,就行估计而言,执行计划对此有很大的估计,因为只有4218行插入到本地临时表中,而不是执行计划认为其正在移动到本地临时表中的248k行。因此,由于这个原因,我在考虑“统计”,但即使约80%的工作是实际插入到表中,这些数据是否仍然重要

我的第一个建议是重新编写整个过程和存储过程,以便不将数据的移动和转换包括到报告存储过程中,并每晚将数据转换到一些持久化表中(不需要实时数据,只需要在前一天结束前的相关数据)。但业务方面不想投入时间和资源进行重新设计,而是“建议”我进行性能调整,以找到我可以在何处添加哪些索引来加速这一过程

我不相信向基表添加索引会提高报告的性能,因为运行查询所需的大部分时间都是将数据保存到临时表中(据我所知,这会影响tempdb,这意味着它们将被写入磁盘->由于I/O延迟而增加的时间)

但是,即使如此,正如我所提到的,这是我的第一个性能调整任务,我在过去几天里尽可能多地阅读了与此相关的内容,这些是我到目前为止的结论,但我想征求更广泛的听众的意见,并希望获得更多的见解和理解,我可以做些什么来改进这个过程

如能回答以下几个明确的问题,我将不胜感激:

  • 我上面所说的(我对db的理解或我的假设)是否有任何错误
  • 向临时表添加索引实际上会增加执行时间,因为每次执行时都会重建表(及其关联的索引),这是真的吗
  • 在这种情况下,是否可以不必重新编写过程/查询,只通过索引或其他调优方法来执行其他操作?(我读过一些文章标题,你也可以“调优tempdb”,但我还没有深入了解这些内容的细节)
非常感谢您的帮助,如果您需要更多详细信息,我将很乐意发布

更新(2016年8月2日):

下面是(部分)有问题的问题。缺少的是
GROUP BY
部分中的几个聚合列及其对应行:

select
    b.ProgramName
    ,b.Region
    ,case when b.AM IS null and b.ProgramName IS not null 
        then 'Unassigned' 
        else b.AM 
    end as AM
    ,rtrim(ltrim(b.Store)) Store
    ,trd.Store_ID
    ,b.appliesToPeriod
    ,isnull(trd.countLeadActual,0) as Actual
    ,isnull(sum(case when b.budgetType = 0 and b.budgetMonth between @start_date and @end_date then b.budgetValue else 0 end),0) as Budget
    ,isnull(sum(case when b.budgetType = 0 and b.budgetMonth between @start_date and @end_date and (trd.considerMe = -1 or b.StoreID < 0) then b.budgetValue else 0 end),0) as CleanBudget
    ... 
into #SalvesVsBudgets
from #StoresBudgets b
    left join #temp_report_data trd on trd.store_ID = b.StoreID and trd.newSourceID = b.ProgramID
where (b.StoreDivision is not null or (b.StoreDivision is null and b.ProgramName = 'NewProgram'))
    group by
        b.ProgramName
        ,b.Region
        ,case when b.AM IS null and b.ProgramName IS not null 
            then 'Unassigned' 
            else b.AM 
        end
    ,rtrim(ltrim(b.Store))
    ,trd.Store_ID
    ,b.appliesToPeriod
    ,isnull(trd.countLeadActual,0)
选择
b、 程序名
,b.区域
,b.AM为null且b.ProgramName不为null时的大小写
然后是“未分配”
其他早餐
以AM结束
,rtrim(ltrim(b.Store))商店
,trd.Store\u ID
,b.appliesToPeriod
,isnull(trd.countLeadActual,0)为实际值
,isnull(总和(当b.budgetType=0且b.budgetMonth介于@start_date和@end_date之间,然后b.budgetValue else 0 end时的情况),0)作为预算
,isnull(当b.budgetType=0且b.budgetMonth介于@start_date和@end_date之间时,以及(trd.considerMe=-1或b.StoreID<0)和b.budgetValue else 0 end时,总和为0)作为CleanBudget
... 
进入#救助计划
来自#StoresBudgets b
在trd.store\u ID=b.StoreID和trd.newSourceID=b.ProgramID上左连接#temp_report_data trd
其中(b.StoreDivision不为null或(b.StoreDivision为null且b.ProgramName='NewProgram'))
分组
b、 程序名
,b.区域
,b.AM为null且b.ProgramName不为null时的大小写
然后是“未分配”
其他早餐
结束
,rtrim(ltrim(b.Store))
,trd.Store\u ID
,b.appliesToPeriod
,isnull(trd.countLeadActual,0)
我不确定这是否真的有用,但由于@kcung请求了它,我添加了信息

另外,要回答他的一些问题:

  • 临时表上没有索引
  • 内存大小:32 GB
更新(2016年8月3日):

我尝试了@kcung的建议,将
CASE
语句从聚合生成查询中移出,但不幸的是,总体而言,程序时间没有明显改善,因为它仍然在±0.25到±1.0秒的范围内波动(是的,与原始版本的存储过程相比,时间更短,时间更长——但我猜这是由于我的机器上的工作负载变化造成的)

同一查询的执行计划现在是:


有没有可能看到查询?以及两个表上的索引? 你的公羊有多大?每只公羊的一排有多大
case when b.AM IS null and b.ProgramName IS not null 
    then 'Unassigned' 
    else b.AM 
end as AM