理解性能的奥秘——应用程序中慢,SSMS中快(4)——收集解决参数嗅探问题的信息
本文属于《理解性能的奥秘——应用程序中慢,SSMS中快》系列
接上文:理解性能的奥秘——应用程序中慢,SSMS中快(3)——不总是参数嗅探的错
虽然已经说明了这个现象的原因,但是还没解释:如何定位和解决这个问题?到目前为止,大家都知道了如何快速处理,如果这个问题很紧急,可以直接使用:
前面提到过,这个操作会刷新计划缓存。下次存储过程被调用时,会产生新的查询计划。如果通过这种方式可以解决,那么认为这个已经不是问题了。
获取必要的事实:
We've been running round in our present stateHoping help will come from above
But even angels there make the same mistakes
- 哪个语句慢?
- 不同的查询计划是怎样的?
- SQL Server嗅探了哪些参数?
- 表和索引的定义是怎样的?
- 统计信息的分布情况如何?实时更新吗?
哪个语句慢?
在SSMS中获取查询计划和参数:
SET ARITHABORT ON go EXEC that_very_sp 4711, 123, 1 go SET ARITHABORT OFF go EXEC that_very_sp 4711, 123, 1
从计划缓存中直接获取查询计划和参数:
查询语句:
DECLARE @dbname NVARCHAR(256),@procname NVARCHAR(256)SELECT @dbname = 'Northwind',@procname = 'dbo.List_orders_11';WITH basedata
AS (SELECT qs.statement_start_offset / 2 AS stmt_start,qs.statement_end_offset / 2 AS stmt_end,est.encrypted AS isencrypted,est.TEXT AS sqltext,epa.value AS set_options,qp.query_plan,charindex('<ParameterList>', qp.query_plan) + len('<ParameterList>') AS paramstart,charindex('</ParameterList>', qp.query_plan) AS paramendFROM sys.dm_exec_query_stats qsCROSS APPLY sys.dm_exec_sql_text(qs.sql_handle) estCROSS APPLY sys.dm_exec_text_query_plan(qs.plan_handle, qs.statement_start_offset, qs.statement_end_offset) qpCROSS APPLY sys.dm_exec_plan_attributes(qs.plan_handle) epaWHERE est.objectid = object_id(@procname)AND est.dbid = db_id(@dbname)AND epa.attribute = 'set_options'),
next_level
AS (SELECT stmt_start,set_options,query_plan,CASE WHEN isencrypted = 1THEN '-- ENCRYPTED'WHEN stmt_start >= 0THEN substring(sqltext, stmt_start + 1, CASE stmt_endWHEN 0THEN datalength(sqltext)ELSE stmt_end - stmt_start + 1END)END AS Statement,CASE WHEN paramend > paramstartTHEN CAST(substring(query_plan, paramstart, paramend - paramstart) AS XML)END AS paramsFROM basedata)
SELECT set_options AS [SET],n.stmt_start AS Pos,n.Statement,CR.c.value('@Column', 'nvarchar(128)') AS Parameter,CR.c.value('@ParameterCompiledValue', 'nvarchar(128)') AS [Sniffed Value],CAST(query_plan AS XML) AS [Query plan]
FROM next_level n
CROSS APPLY n.params.nodes('ColumnReference') AS CR(c)
ORDER BY n.set_options,n.stmt_start,Parameter
如果再次之前你从来没用过DMVs,估计对你而言会有点难懂。但是为了把注意力集中在我们的主题上。在这里需要提醒的是语句中需要制定数据库和存储过程名。
结果输出:
USE Northwind
GOCREATE PROCEDURE List_orders_11 @fromdate DATETIME,@custid NCHAR(5)
AS
SELECT @fromdate = dateadd(YEAR, 2, @fromdate)SELECT *
FROM Orders
WHERE OrderDate > @fromdateAND CustomerID = @custidIF @custid = 'ALFKI'CREATE INDEX test ON Orders (ShipVia)SELECT *
FROM Orders
WHERE CustomerID = @custidAND OrderDate > @fromdateIF @custid = 'ALFKI'DROP INDEX testON Orders
GOSET ARITHABORT ONEXEC List_orders_11 '19980101','ALFKI'
GOSET ARITHABORT OFFEXEC List_orders_11 '19970101','BERGS'
- SET——表示查询计划中set_options属性。正如前面提到的,这是一个位掩码。上图中可以看到两个值:251 为默认设置,4347为默认设置+ARITHABORT ON。如果看到其他值,可以用作者编写的一个函数反编译:setoptions 。
- Pos——表示该语句在存储过程的起始位置,从存储过程创建语句起算,包括任何CREATE PROCEDURE之前的注释。虽然大部分情况下作用不大,但是可以看到语句在存储过程中的出现顺序。
- Statement——SQL语句,但是注意对于每个参数,都会重复一次。
- Parameter——参数名,仅列出语句中出现的参数。也就是说,如果该查询语句没有使用到的参数,是不会出现在这里的。
- Sniffed Value——在编译时的参数值,也就是在嗅探优化并产生查询计划的参数值。因为这是从计划缓存中获取的信息,所以这里的值并不是实际参数值,从上图中可以看到,对于不同的语句可能会出现不同的参数值。
- Query Plan——对应的预估执行计划。
从Trace文件中获取查询计划和参数:
获取表和索引的定义:
DECLARE @tbl NVARCHAR(265)SELECT @tbl = 'Orders'SELECT o.NAME,i.index_id,i.NAME,i.type_desc,substring(ikey.cols, 3, len(ikey.cols)) AS key_cols,substring(inc.cols, 3, len(inc.cols)) AS included_cols,stats_date(o.object_id, i.index_id) AS stats_date,i.filter_definition
FROM sys.objects o
JOIN sys.indexes iON i.object_id = o.object_id
CROSS APPLY (SELECT ', ' + c.NAME + CASE ic.is_descending_keyWHEN 1THEN ' DESC'ELSE ''ENDFROM sys.index_columns icJOIN sys.columns cON ic.object_id = c.object_idAND ic.column_id = c.column_idWHERE ic.object_id = i.object_idAND ic.index_id = i.index_idAND ic.is_included_column = 0ORDER BY ic.key_ordinalFOR XML PATH('')) AS ikey(cols)
OUTER APPLY (SELECT ', ' + c.NAMEFROM sys.index_columns icJOIN sys.columns cON ic.object_id = c.object_idAND ic.column_id = c.column_idWHERE ic.object_id = i.object_idAND ic.index_id = i.index_idAND ic.is_included_column = 1ORDER BY ic.index_column_idFOR XML PATH('')) AS inc(cols)
WHERE o.NAME = @tblAND i.type IN (1,2)
ORDER BY o.NAME,i.index_id
这个语句仅用于常规关系型索引,不适合XML索引和空间索引。
获取统计信息相关信息:
DECLARE @tbl NVARCHAR(265)SELECT @tbl = 'Orders'SELECT o.NAME,s.stats_id,s.NAME,s.auto_created,s.user_created,substring(scols.cols, 3, len(scols.cols)) AS stat_cols,stats_date(o.object_id, s.stats_id) AS stats_date,s.filter_definition
FROM sys.objects o
JOIN sys.stats sON s.object_id = o.object_id
CROSS APPLY (SELECT ', ' + c.NAMEFROM sys.stats_columns scJOIN sys.columns cON sc.object_id = c.object_idAND sc.column_id = c.column_idWHERE sc.object_id = s.object_idAND sc.stats_id = s.stats_idORDER BY sc.stats_column_idFOR XML PATH('')) AS scols(cols)
WHERE o.NAME = @tbl
ORDER BY o.NAME,s.stats_id
其中列stats_date返回统计信息最近更新时间。如果这个时间已经过去很久,那么统计信息可能已经过时。参数嗅探问题的根源通常不是统计信息过时,但是也应该检查一下。需要记住的是,统计信息的列如果是单调递增——如ID、date列,那么会很快过时,因为语句通常获取最近插入的数据,在统计信息的直方图中,记录的却通常是旧的数据。关于直方图会在后续介绍。
UPDATE STATISTICS 表名 WITH FULLSCAN, INDEX
UPDATE STATISTICS tbl indexname WITH FULLSCAN
注意:在表名和索引名之间没有句号,只有空格。
如果是统计信息过时导致的性能问题,通常在更新统计信息之后,就可以发现应用程序的性能马上就得到提升。因为统计信息的更新会触发重编译,使得存储过程会对参数重新嗅探并产生更好的执行计划。
DBCC SHOW_STATISTICS (Orders, OrderDate)
小结:
理解性能的奥秘——应用程序中慢,SSMS中快(4)——收集解决参数嗅探问题的信息相关推荐
- 《深入理解计算机系统》之浅析程序性能优化
此文已由作者余笑天授权网易云社区发布. 欢迎访问网易云社区,了解更多网易技术产品运营经验. 本文主要是基于我之前学习<深入理解计算机系统>(以下简称CSAPP)这本书第五章优化程序性能内容 ...
- keil c语言 延迟程序,Keil C51程序设计中几种精确延时方法
前几天时间在做一个基于51单片机开发板的等精度频率计,用LCD1602液晶显示的,晶振是22.1184MHZ,用得是测频率法,目的是想做到能够测试0--900KHZ的信号. 液晶显示部分花了我好几天才 ...
- razor imu 9dof的使用,先锋机器人rosaria 理解,配置STM32-ROS通信等疑难杂症(持续更新中)
本文由 \color{blue}{\bf本文由} @DavidHan\color{red}{\it @David Han}出品,转载请注明出处\color{blue}{ \bf出品 ,转载请注明出处} ...
- c 语言如何处理表格文件中的数据库,C#程序从Excel表格中读取数据并进行处理
今天做了一个Excel表格数据处理的事情,因为数据量表较大(接近7000条)所以处理起来有点麻烦,于是写了一个程序, 先将程序记下以便将来查找. using System; using System. ...
- .NET程序在Linux容器中的演变
本文讲的是.NET程序在Linux容器中的演变[编者的话]Linux容器技术已被开发人员所熟知,现在.NET程序可以跑在Docker容器中,这为以Windows中心的开发人员带来了好处. [上海站|3 ...
- 哪个是python程序中与缩进有关的正确说法_关于Python程序中与“缩进”有关的说法中,以下选项中正确的是()。_学小易找答案...
[单选题]白内障的主要症状 [多选题]白内障病人手术后护理重点观察是 [单选题]某女,21岁.排球比赛时与队员发生碰撞,后诉鼻梁疼痛来院就诊,检查鼻腔发现鼻中隔有一小血肿.正确处理方法是 [单选题]开 ...
- 《LoadRunner 没有告诉你的》之四——理解性能
本文是<LoadRunner没有告诉你的>系列文章的第四篇,在这篇短文中,我将尽可能用简洁清晰的文字写下我对"性能"的看法,并澄清几个容易混淆的概念,帮助大家更好的理解 ...
- 对linux中多线程编程中pthread_join的理解
对linux中多线程编程中pthread_join的理解 分类: 程序员面试 linux学习2013-08-04 21:32 234人阅读 评论(0) 收藏 举报 多线程linuxpthread_jo ...
- 计算机语言的比较英文论文,科学网—撰写高质量英文科技论文的心态、布局、程序和方法 - 岳中琦的博文...
撰写高质量英文科技论文的心态.布局.程序和方法 岳中琦 高质量科技论文,是将我们自己的创新研究成果,在现在或将来被全世界人知道和应用.成为人类已知的知识和实践.因此,我们在撰写科技论文时要具备一种极其 ...
最新文章
- 《数学之美》第1章 文字和语言 vs 数字和信息
- 用一句JQuery代码实现表格的简单筛选
- sgu 207 Robbers
- leetcode 303. Range Sum Query - Immutable | 303. 区域和检索 - 数组不可变(一维前缀和问题)
- 开源项目管理软件禅道使用帮助下载
- qt 串口 环形缓存_qt linux串口 缓冲区多大
- 作者:杨波,山东农业大学硕士生。
- numpy的常用函数 不断更新
- 10天确定Python,运行环境(超详细步骤)
- 【Java从0到架构师】JS_jQuery_BootStrap
- [BUG] CS0234: 命名空间“System.Web.Mvc”中不存在类型或命名空间名称“Ajax”(是否缺少程序集引用?)...
- 草料二维码 批量生成二维码
- FireFox把Gmail变成大容量网络硬盘
- APP自动化测试-3. Appium元素定位与等待
- 抽象类和接口的区别(之二)
- VS2019番茄助手添加头文件防重复宏定义#ifn
- web前端开发主要培训哪些内容
- Bluetooth协议学习
- Kibana查询语言(KQL)AND、OR匹配,模糊匹配
- PTA 数组 7-5 按字母顺序排列出场国家名称