SQL Server如何定位自定义标量函数被那个SQL调用次数最多浅析
前阵子遇到一个很是棘手的问题,监控系统DPA发现某个自定义标量函数被调用的次数非常高,高到一个离谱的程度。然后在Troubleshooting这个问题的时候,确实遇到了一些问题让我很是纠结,下文是解决问题过程的一点思索和尝试,如果你有更好的思路和解决方法,也请多多指教。
DPA可以监控到该函数每小时被调用的次数,如下截图所示:
那么第一个问题来了。 DPA如何监控获取这个函数每小时执行多少次呢? 其实这个很简单, sys.dm_exec_query_stats视图里面有个字段execution_count 统计SQL的执行次数,但是它记录的是计划自上次编译以来所执行的次数。那么,我整点执行两次结果的差值(execution_count的差值)就是一小时内的执行次数。
execution_count Number of times that the plan has been executed since it was last compiled.(计划自上次编译以来所执行的次数。)
这个我们可以试验一下,如下所示,在AdventureWorks2014,我们创建一个自定义标量函数,然后我们
USE AdventureWorks2014;
GO
CREATE FUNCTION Sales.FetchProductOrderNum
(
@ProuctID INT
) RETURNS INT
BEGIN
DECLARE @SaleOrderNum INT;
SELECT @SaleOrderNum=COUNT(SalesOrderID) FROM Sales.SalesOrderDetail
WHERE ProductID=@ProuctID
GROUP BY ProductID;
RETURN @SaleOrderNum;
END
GO
DBCC FREEPROCCACHE; --删除计划缓存中的所有元素
GO
DECLARE @ProductID INT;
SET @ProductID=870
SELECT DISTINCT ProductID, Sales.FetchProductOrderNum(ProductID) FROM Sales.SalesOrderDetail
WHERE ProductID=@ProductID
SELECT qs.plan_handle
, OBJECT_NAME(qt.objectid)
, qs.execution_count AS [Execution Count]
, qs.execution_count / DATEDIFF(Second, qs.creation_time, GETDATE()) AS [Calls/Second]
, qs.total_worker_time / qs.execution_count AS [AvgWorkerTime]
, qs.total_worker_time AS [TotalWorkerTime]
, qs.total_elapsed_time / qs.execution_count AS [AvgElapsedTime]
, qs.max_logical_reads
, qs.max_logical_writes
, qs.total_physical_reads
, DATEDIFF(Minute, qs.creation_time, GETDATE()) AS [Age in Cache]
FROM
sys.dm_exec_query_stats AS qs
CROSS APPLY
sys.dm_exec_sql_text(qs.[sql_handle]) AS qt
WHERE
qt.[dbid] = DB_ID()
AND qt.objectid = OBJECT_ID('Sales.FetchProductOrderNum')
OPTION (RECOMPILE);
DECLARE @ProductID INT;
SET @ProductID=897
SELECT DISTINCT ProductID, Sales.FetchProductOrderNum(ProductID) FROM Sales.SalesOrderDetail
WHERE ProductID=@ProductID
DECLARE @ProductID INT;
SET @ProductID=870
SELECT DISTINCT ProductID, Sales.FetchProductOrderNum(ProductID) FROM Sales.SalesOrderDetail
WHERE ProductID=@ProductID
如上所示,假设一个小时内只执行了上面两个SQL,那么我知道这个自定义函数被调用了 9378 - 4688 =4690次。 所以基于这种规则,就可以找出一小时内自定义函数的调用次数,当然其它数据库对象也可以如此计算。
那么接下来的问题,一个数据库中有多脚本都调用了这个自定义标量函数,但是我怎么判别、区分那个SQL脚本调用了自定义函数最多(或者能查出TOP 10 SQL语句),这个问题纠结了好久,查找了好多资料,均无法实现这个功能。
为什么有这样的需求呢? 因为,不能定位那个SQL调用的次数最多,我无法定位问题根源,我遇到的案例,发现有接近200个地方调用这个自定义函数,如果一个个去判断分析、这个是个累死人的体力活,而且有些SQL非常不容易确定
会调用多少次,(例如有些是在临时表上调用该函数, 有些条件是传入的变量等等)。
SELECT TOP 120
SUBSTRING(qt.text, ( qs.statement_start_offset / 2 ) + 1,
( ( CASE qs.statement_end_offset
WHEN -1 THEN DATALENGTH(qt.text)
ELSE qs.statement_end_offset
END - qs.statement_start_offset ) / 2 ) + 1) ,
qt.text ,
qs.execution_count ,
qs.total_logical_reads ,
qs.last_logical_reads ,
qs.total_logical_writes ,
qs.last_logical_writes ,
qs.total_worker_time ,
qs.last_worker_time ,
qs.total_elapsed_time / 1000000 total_elapsed_time_in_S ,
qs.last_elapsed_time / 1000000 last_elapsed_time_in_S ,
qs.last_execution_time ,
qp.query_plan
FROM sys.dm_exec_query_stats qs
CROSS APPLY sys.dm_exec_sql_text(qs.sql_handle) qt
CROSS APPLY sys.dm_exec_query_plan(qs.plan_handle) qp
WHERE qt.text LIKE '%FunctionName%'
ORDER BY qs.execution_count DESC;
如果你用这样的SQL语句,也是无法找到那个SQL调用自定义函数次数最多(自定义标量函数的特性,不清楚的可以看看我这篇博客SQL SERVER中用户定义标量函数(scalar user defined function)的性能问题),这里不做过细介绍。后面我发现如果那个SQL调用自定义标量函数过多,它的逻辑读是非常高的。当然这个不是非常精准,而且也需要在一定范围内进行甄别,不过在这个范围内做了一个范围刷选,已经非常难得了,在我这个案例当中,我非常顺速的对几个SQL进行判断、甄别后,就快速找到了调用次数非常多的SQL。这个已经是我能找到最好的方法了。如果其它更好的方法,欢迎指点一二!
SELECT TOP 120
SUBSTRING(qt.text, ( qs.statement_start_offset / 2 ) + 1,
( ( CASE qs.statement_end_offset
WHEN -1 THEN DATALENGTH(qt.text)
ELSE qs.statement_end_offset
END - qs.statement_start_offset ) / 2 ) + 1) ,
qt.text ,
qs.execution_count ,
qs.total_logical_reads ,
qs.last_logical_reads ,
qs.total_logical_writes ,
qs.last_logical_writes ,
qs.total_worker_time ,
qs.last_worker_time ,
qs.total_elapsed_time / 1000000 total_elapsed_time_in_S ,
qs.last_elapsed_time / 1000000 last_elapsed_time_in_S ,
qs.last_execution_time ,
qp.query_plan
FROM sys.dm_exec_query_stats qs
CROSS APPLY sys.dm_exec_sql_text(qs.sql_handle) qt
CROSS APPLY sys.dm_exec_query_plan(qs.plan_handle) qp
WHERE qt.text LIKE '%FunctionName%'
--ORDER BY qs.execution_count DESC;
ORDER BY qs.total_logical_reads DESC
--ORDER BY qs.last_logical_reads 有时按last_logical_reads更精准
我们来验证一下我们上面测试的案例,如下所示, 你会看到本身Sales.FetchProductOrderNum这个自定义标量函数的调用次数才是最多的,所以如果按execution_count来统计,这个是完全不行的,例如其中一个SQL执行一次(ProductID=870),Sales.FetchProductOrderNum标量函数就要被调用好几千次,而按照了逻辑读(total_logical_reads或last_logical_reads)来分析,基本上就能定位到调用标量函数次数最多的SQL了。当然实际环境远远比这个测试案例复杂的多。
SQL Server如何定位自定义标量函数被那个SQL调用次数最多浅析的更多相关文章
- SQL SERVER中用户定义标量函数(scalar user defined function)的性能问题
用户定义函数(UDF)分类 SQL SERVER中的用户定义函数(User Defined Functions 简称UDF)分为标量函数(Scalar-Valued Function)和表值函数(T ...
- SQL SERVER 2005允许自定义聚合函数-表中字符串分组连接
不多说了,说明后面是完整的代码,用来将字符串型的字段的各行的值拼成一个大字符串,也就是通常所说的Concat 例如有如下表dict ID NAME CATEGORY 1 RED COLOR ...
- SQL SERVER 2005允许自定义聚合函数
不多说了,说明后面是完整的代码,用来将字符串型的字段的各行的值拼成一个大字符串,也就是通常所说的Concat 例如有如下表dict ID NAME CATEGORY 1 RED COLOR ...
- EntityFramework Core 2.0自定义标量函数两种方式
前言 上一节我们讲完原始查询如何防止SQL注入问题同时并提供了几种方式.本节我们继续来讲讲EF Core 2.0中的新特性自定义标量函数. 自定义标量函数两种方式 在EF Core 2.0中我们可以将 ...
- SQL Server 2019 中标量用户定义函数性能的改进
在SQL Server中,我们通常使用用户定义的函数来编写SQL查询.UDF接受参数并将结果作为输出返回.我们可以在编程代码中使用这些UDF,并且可以快速编写查询.我们可以独立于任何其他编程代码来修改 ...
- SQL Server利用RowNumber()内置函数与Over关键字实现通用分页存储过程(支持单表或多表结查集分页)
SQL Server利用RowNumber()内置函数与Over关键字实现通用分页存储过程,支持单表或多表结查集分页,存储过程如下: /******************/ --Author:梦在旅 ...
- (转载)MS SQL Server 未公开的加密函数有哪些?
MS SQL Server 未公开的加密函数有哪些? 以下的文章是对MS SQL Server 未公开的加密函数的具体操作,如果你对其相关的实际操作有兴趣的话,你就可以点击了. MS SQL Serv ...
- SQL Server中的CLR编程——用.NET为SQL Server编写存储过程和函数
原文:SQL Server中的CLR编程--用.NET为SQL Server编写存储过程和函数 很早就知道可以用.NET为SQL Server2005及以上版本编写存储过程.触发器和存储过程的,不过之 ...
- SQL SERVER 提供了一些时间函数:
SQL SERVER 提供了一些时间函数:取当前时间:select getdate()取前一个月的时间:SELECT DATEADD(MONTH,-1,GETDATE()) 月份减一个月取年份:SEL ...
随机推荐
- Java并发编程-AbstractQueuedSynchronizer源码分析
简介 提供了一个基于FIFO队列,可以用于构建锁或者其他相关同步装置的基础框架.该同步器(以下简称同步器)利用了一个int来表示状态,期望它能够成为实现大部分同步需求的基础.使用的方法是继承,子类通过 ...
- springmvc 项目完整示例09 maven项目创建
需求表均同springmvc案例 此处只是使用maven 注意,以下所有需要建立在你的eclipse等已经集成配置好了maven了,说白了就是新建项目的时候已经可以找到maven了 没有的话需要安装m ...
- shiro源码篇 - shiro的session创建,你值得拥有
前言 开心一刻 开学了,表弟和同学因为打架,老师让他回去叫家长.表弟硬气的说:不用,我打得过他.老师板着脸对他说:和你打架的那位同学已经回去叫家长了.表弟犹豫了一会依然硬气的说:可以,两个我也打得过. ...
- Perl的比较操作符
比较操作符 perl的比较操作符和bash完全相反.数值比较采用符号,字符串比较采用字母. 数值 字符串 意义 ----------------------------- == eq 相等 != ne ...
- python列表类型
列表类型简介 列表类型是一个容器,它里面可以存放任意数量.任意类型的数据. 例如下面的几个列表中,有存储数值的.字符串的.内嵌列表的.不仅如此,还可以存储其他任意类型. >>> L ...
- java当中的强引用,软引用,弱引用,虚引用
强引用,软引用,弱引用,虚引用:不同的引用类型主要体现在GC上 强引用:如果一个对象具有强引用,它就不会被垃圾回收器回收.即使当前内存空间不足,JVM也不会回收它,而是抛出 OutOfMemoryEr ...
- 一个小时学会Maven
一.为什么要Maven 在开发中经常需要依赖第三方的包,包与包之间存在依赖关系,版本间还有兼容性问题,有时还里要将旧的包升级或降级,当项目复杂到一定程度时包管理变得非常重要. Maven是当前最受欢迎 ...
- SQL Server 怎么在分页获取数据的同时获取到总记录数
SQL Server 获取数据的总记录数,有两种方式: 1.先分页获取数据,然后再查询一遍数据库获取到总数量 2.使用count(1) over()获取总记录数量 SELECT * FROM ( SE ...
- C# CLR via 对象内存中堆的存储【类型对象指针、同步块索引】
最近在看书,看到了对象在内存中的存储方式. 讲到了对象存储在内存堆中,分配的空间除了类型对象的成员所需的内存量,还有额外的成员(类型对象指针. 同步块索引 ),看到这个我就有点不懂了,不知道类型对象指 ...
- UML 序列图
序列图 序列图主要用于按照交互发生的一系列顺序,显示对象之间的这些交互.显示不同的业务对象如何交互,对于交流当前业务如何进行很有用.序列图是一个用来记录系统需求,和整理系统设计的好图.序列图 ...