最近在优化数据库服务器上高消耗语句/过程,发现一个存储过程优化后依旧出现在Profiler跟踪里。将Profiler跟踪文件中过程执行语句取出,打开一个查询窗口(SPID=144),set statistics io on,同时开启Profiler跟踪SPID=144中的语句执行情况。
下面是在查询窗口的执行结果,逻辑读只有17:

我们再看Profiler跟踪窗口的结果:

此处的CPU(1216)、Reads(160206)相比查询窗口中的逻辑读高出很多。查看存储过程相应部分对应的语句,仅仅是两个表关联查询而已:

如果直接执行存储过程中的语句会是怎样的呢?首先,按照过程参数传递的形式,将必要的参数Declare,执行:

其次,将参数用具体数值代替,再次执行:

以上两图中逻辑读没发现什么区别,但我们转到Profiler跟踪窗口,单独执行存储过程中的查询语句,如果top N 是以参数形式传入其cpu、reads与执行存储过程的消耗差不多,但比top 具体值的cpu、reads高很多:

此时我们应该想到它们的执行计划是不同的,从Profiler结果可以看出这块的消耗可以通过具体值,或在语句结尾+option(recompile)来降低。
下面我们将@typeid=2这一段封装到测试存储过程,然后分别查看语句末尾有无+option(recompile),执行此存储过程并查看执行计划。首先,我们对@typeid=2中的语句不做任何修改,模拟原过程执行情况:

然后,我们在查询语句的末尾加上+option(recompile),让其执行到此语句时,重编译:

注意到了没有,两者使用的索引完全一样,但它们在Profiler跟踪里的消耗却相差甚大。重编译在排序操作返回的记录数(228)较原过程的排序操作返回的记录数(47331)少很多,它直接影响对表u上idx_userID的执行次数。推测就是对u的执行次数,导致两个语句在Profiler跟踪里的消耗悬殊。
实际上不管是执行存储过程还是单独执行语句,在查询窗口的消息信息中没有表u的逻辑读取信息:

依据执行计划,肯定有对u表的读取操作,为什么在set statistics io on时,它没有出现?什么情况下会出现这种情况呢?
优化心得
使用RML分析.TRC文件真的很方便,我们可以按照下面的步骤来分析数据库服务器上高消耗的语句:
1、开启服务器端跟踪收集一段时间的数据(例如18:00~次日06:00,cpu>=33,根据情况调整)
2、使用RML工具分析跟踪数据(.TRC),很多存储过程调用或动态语句总体是一样的,只是带的参数会有不同,这个工具会把它们归类
3、根据归类,优先将总消耗大的语句优化
4、RML分析报表以图表展示,支持导出到execl、word、pdf;也可以用语句直接从库下获取符合需求的语句
下面代码提取[按照同一类型的语句,统计最昂贵的语句]:

--使用RML Cmd Prompt导入跟踪数据
ReadTrace -I"F:\TroubleShooting\Trace\HostName_InstanceName_HighCPU33_after.trc" -o"F:\TroubleShooting\Trace\output" -S"127.0.0.1,7777" -d"PerfAnalysis" -E USE PerfAnalysis
GO
--查询跟踪
select MIN(StartTime),MAX(EndTime),COUNT(*)
from fn_trace_gettable(N'F:\TroubleShooting\Trace\HostName_InstanceName_HighCPU33_after.trc', default)
where cpu is not null select * from ReadTrace.tblTimeIntervals
select top 10 * from ReadTrace.tblBatchPartialAggs
select top 10 * from ReadTrace.tblUniqueBatches --最初是按HashID得到总消耗CPU、Duration、Reads、Writes前N的语句
--后期根据需求添加DBID、LoginNameID,还可以计算平均消耗
select *,
row_number() over(order by sum_CPU_ms desc) as QueryNumber
from (
select --a.HashID,
sum(CompletedEvents) as Executes,
sum(TotalCPU) as sum_CPU_ms,
sum(TotalCPU)/sum(CompletedEvents) as avg_CPU_ms,--add
sum(TotalDuration)/1000 as sum_Duration_ms,
sum(TotalDuration)/(sum(CompletedEvents)*1000) as avg_Duration_ms,--add
sum(TotalReads) as sum_Reads,
sum(TotalReads)/sum(CompletedEvents) as avg_Reads,--add
sum(TotalWrites) as sum_Writes,
sum(TotalWrites)/sum(CompletedEvents) as avg_Writes,--add
--sum(AttentionEvents) as sum_Attentions,
--(select StartTime from ReadTrace.tblTimeIntervals i where TimeInterval = @StartTimeInterval) as [StartTime],
--(select EndTime from ReadTrace.tblTimeIntervals i where TimeInterval = @EndTimeInterval) as [EndTime],
--add DatabaseName、LoginName
(select distinct DatabaseName from fn_trace_gettable(N'F:\TroubleShooting\Trace\HostName_InstanceName_HighCPU33_after.trc', default) where DatabaseID=a.DBID) as DatabaseName,
(select LoginName from ReadTrace.tblUniqueLoginNames where iID=a.LoginNameID) as LoginName,
(select cast(NormText as nvarchar(4000)) from ReadTrace.tblUniqueBatches b where b.HashID = a.HashID) as [NormText],
row_number() over(order by sum(TotalCPU) desc) as CPUDesc,
row_number() over(order by sum(TotalCPU) asc) as CPUAsc,
row_number() over(order by sum(TotalDuration) desc) as DurationDesc,
row_number() over(order by sum(TotalDuration) asc) as DurationAsc,
row_number() over(order by sum(TotalReads) desc) as ReadsDesc,
row_number() over(order by sum(TotalReads) asc) as ReadsAsc,
row_number() over(order by sum(TotalWrites) desc) as WritesDesc,
row_number() over(order by sum(TotalWrites) asc) as WritesAsc
from ReadTrace.tblBatchPartialAggs a
--where TimeInterval @StartTimeInterval and @EndTimeInterval
--and a.AppNameID = isnull(@iAppNameID, a.AppNameID)
--and a.LoginNameID = isnull(@iLoginNameID, a.LoginNameID)
--and a.DBID = isnull(@iDBID, a.DBID)
group by a.HashID,a.DBID,a.LoginNameID
) as Outcome
where (CPUDesc <= 20
--or CPUAsc <= @TopN
or DurationDesc <= 20
--or DurationAsc <= @TopN
or ReadsDesc <= 20
--or ReadsAsc <= @TopN
or WritesDesc <= 20
--or WritesAsc <= @TopN
)
order by sum_CPU_ms desc
option (recompile) select top 100 EventClass,TextData,DatabaseName,DatabaseID,Duration/1000 Duration_ms,CPU CPU_ms,Reads,Writes,StartTime,EndTime,HostName,LoginName,ApplicationName
from fn_trace_gettable(N'F:\TroubleShooting\Trace\HostName_InstanceName_HighCPU33_after.trc', default)
where TextData like '%GAMEWEB_ADMIN_GAMESCORE_LOG%'

代码对应的是RML报表的Top Unique Batches页面,同时增加对数据库、应用程序分组,以及平均消耗值信息。部分组件导出到execl、word、pdf时报错,可以使用语句直接从数据库下提取消耗列表。

Top (参数)的更多相关文章

  1. linux TOP参数

    TOP参数 top - 01:06:48 up  1:22,  1 user,  load average: 0.06, 0.60, 0.48Tasks:  29 total,   1 running ...

  2. ADO.NET一小记-select top 参数问题

    异常处理汇总-后端系列 http://www.cnblogs.com/dunitian/p/4523006.html 最近使用ADO.NET的时候,发现select top @count xxxx 不 ...

  3. linux top 参数详解

    top命令是Linux下常用的性能分析工具,能够实时显示系统中各个进程的资源占用状况,类似于Windows的任务管理器.下面详细介绍它的使用方法. top - 01:06:48 up  1:22,   ...

  4. linux命令TOP参数load average详解[转]

    我们知道判断一个系统的负载可以使用top,uptime等命令去查看,它分别记录了一分钟.五分钟.以及十五分钟的系统平均负载……我们知道判断一个系统的负载可以使用top,uptime等命令去查看,它分别 ...

  5. 每天一个linux命令(44):top命令

    top命令是Linux下常用的性能分析工具,能够实时显示系统中各个进程的资源占用状况,类似于Windows的任务管理器.下面详细介绍它的使用方法.top是一个动态显示过程,即可以通过用户按键来不断刷新 ...

  6. Linux命令--top使用技巧

    摘自 http://www.jb51.net/LINUXjishu/151995.html top命令是Linux下常用的性能分析工具,能够实时显示系统中各个进程的资源占用情况,类似于Windows的 ...

  7. 每天一个linux命令(36):top命令

    top命令是Linux下常用的性能分析工具,能够实时显示系统中各个进程的资源占用状况,类似于Windows的任务管理器.下面详细介绍它的使用方法.top是 一个动态显示过程,即可以通过用户按键来不断刷 ...

  8. Linux之top命令

    top命令是Linux下常用的性能分析工具,能够实时显示系统中各个进程的资源占用状况,类似于Windows的任务管理器.下面详细介绍它的使用方法.top是一个动态显示过程,即可以通过用户按键来不断刷新 ...

  9. 【Linux】之系统工具top

    top命令是Linux下常用的性能分析工具,能够实时显示系统中各个进程的资源占用状况,类似于Windows的任务管理器.下面详细介绍它的使用方法.top是一个动态显示过程,即可以通过用户按键来不断刷新 ...

随机推荐

  1. IOS之同步请求、异步请求、GET请求、POST请求

    .同步请求可以从因特网请求数据,一旦发送同步请求,程序将停止用户交互,直至服务器返回数据完成,才可以进行下一步操作, .异步请求不会阻塞主线程,而会建立一个新的线程来操作,用户发出异步请求后,依然可以 ...

  2. CentOS6.4 增加一个SFTP上传的用户

    #创建sftp组 groupadd sftp #创建一个用户dsideal useradd -g sftp -s /bin/false dsideal #设置dsideal用户的密码 passwd d ...

  3. ACM D的小L

    D的小L 时间限制:4000 ms  |  内存限制:65535 KB 难度:2   描述       一天TC的匡匡找ACM的小L玩三国杀,但是这会小L忙着哩,不想和匡匡玩但又怕匡匡生气,这时小L给 ...

  4. Codeforces Round #209 (Div. 2) B. Permutation

    解题思路: 如果序列a是单调递增的,则序列为1,2,..... 2n,则将给出的式子化简得Σ(a2i - a2i-1) = n 如果序列a是单调递减的,则序列为2n,.........2, 1,则将给 ...

  5. 【JAVA】Quartz 任务调度和异步执行器

    Quartz基础结构         Quartz对任务调度的领域问题进行了高度抽象,提出了调度器(Scheduler).任务(Job)和触发器(Trigger)这3个核心概念,并在Trigger触发 ...

  6. Flash与JS之间相互调用以及参数传递

    [AS3]ExternalInterface.call传多个参数的写法代码示例 import flash.text.TextField; ; ; var result:uint = ExternalI ...

  7. HTML 父窗口打开子窗口,并从子窗口返回值

    父窗口:windowdemo.html <html> <head> <title> 接收子窗口返回的内容 </title> <script lan ...

  8. js判断三个数字中的最大值

    <script> //方法一: function maxOf3(c,d,e){ return (((c>d)?c:d)>e ? ((c>d)?c:d) : e); } c ...

  9. 当target属性在XHTML script中无效时

    <a href="#" target=_blank></a>target此属性能够使链接在新窗口打开,但是在XHTML script中无效时. 那么解决方案 ...

  10. 内置函数----整理、例题 、xmin

    -----------数值函数 ---绝对值 select abs(-123) from dual; --求模 select mod (12,5) from dual; --取整 --上限值 sele ...