4 .3 .4 常见高CPU利用率的原因

4 .3 .4 常见高CPU利用率的原因
存在髙CPU利用率的问题类型有很多种,但是我们可以关注一些常见类型,至于其他
极端类型暂时不包含。以下便是高CPU利用率的常见类型:
□缺失索引(Missing Index)
□统计信息过时
□ 非 SARG查询
□ 隐式 转 换 (Implicit conversions □ 参数嗅探(Parameter sniffing)
□非参数化Ad-hoc査询 □非必要的并行查询
下面分别介绍一下。
1 . 缺失索引
缺失索引是最常见的引起髙CPU和 I/O利用的原因之一,当没有合适的索引用于支
持查询时,一般只能通过大面积扫描来获取所需的信息。一方面,这种扫描会造成SQL
Server需要处理很多非必要的数据;另外一方面,由于需要加载很多非必要的数据到内存, 因此会引起内存压力,导致计划缓存被移除,更严重的是引起SQL Server必须重新编译、 优化查询,编译和优化也是高CPU开销操作。下面来看个例子,执行如下语句。
USE AdventureWorks2008R2 GO

SET STATISTICS TIME ON;
SET STATISTICS IO ON;
SELECT per.FirstName , per.LastName , p.Name , p .ProductNumber , OrderDate , LineTotal ? soh.TotalDue FROM Sales.SalesOrderHeader AS soh INNER JOIN Sales.SalesOrderDetail sod ON soh.SalesOrderlD = sod.SalesOrderlD INNER JOIN Production.Product AS p ON sod.ProductlD = p.ProductID INNER JOIN Sales.Customer AS c ON soh.CustomerlD = c.CustomerlD INNER JOIN Person.Person AS per ON c.PersonlD = per.BusinessEntitylD WHERE LineTotal > 25000
SET STATISTICS IO OFF;
SET STATISTICS TIME OFF;
得 到 下 面 的 信 息 ,
SQL Server执行时间:
C P U 时间= 0 毫秒,占用时间= 0 毫秒。
SQL Server执行时间:
C P U 时间= 6 2 毫秒,占用时间= 9 7 毫秒。
SQL Server执行时间:
C P U 时间= 0 毫秒,占用时间= 0 毫秒。
可以看到,由于缺少索引,CPU需要花费很多时间去获取不必要的数据。我们可以创
建一个索引,然后再看看结果。
CREATE NONCLUSTERED INDEX idx_SalesOrderDetail_LineTotal ON Sales.SalesOrderDetail (LineTotal)
索 引 后 结 果 如 下 ,
SQL Server执行时间:
CPU时间= 0 毫秒,占用时间= 0 毫秒。
SQL Server执行时间:
CPU时间= 0 毫秒,占用时间= 1 毫秒。
SQL Server执行时间:
C P U 时间= 0 毫秒,占用时间= 0 毫秒。
有了索引,占用时间几乎为0 , 可见效果很明显。在本人的工作经历中,缺失索引是最
常见的CPU消耗原因。

2. 统计信息过时
SQL Server优化器借助统计信息来预估查询情况,如果统计信息过时、不准 确 ,会导 致优化器产生不合适的执行计划,比如表中只有几万数据,而统计信息显示有几亿,这时
候优化器可能会选择hash连接,这将加大各方面的资源开销。对于这类问题,可以在通过 执行计划来查看,如果一个查询,你明知道它返回和处理的结果集都很小,而优化器却选
择了 hash连接,那么这时就可以检查一下图形化执行计划中是否有黄色叹号,或者用文本 化执行计划看看预估和实际行数的差异是否很大。如果是,可以使用UPDATE STATISTICS
语句更新统计信息,同时检查为什么统计信息过时。
3. 非 SARG查询
SARG是 Search Argument的缩写。简单来说,如果一个谓词(特别是WHERE条件
中)能用到索引查找操作,就可以理解为符合SARG。但是如果在WHERE条件所用到的
列中使用了标量函数(YEAR、UPPER等),或者使用了 LIKE ?%%’这类的查询,就称为非
SARG査询,会导致索引无效。这些非SARG的写法使得SQL Server只能进行表或者索引 扫描,结果类似于缺失索引,所以同样会引起CPU高利用。下面是典型的非SARG查询:
SELECT soh.SalesOrderlD , OrderDate , DueDate , ShipDate , Status , SubTotal ,
TaxAmt ,
Freight , TotalDue FROM Sales.SalesOrderheader AS soh INNER JOIN Sales.SalesOrderDetail AS sod ON soh.SalesOrderlD = sod.SalesOrderlD WHERE CONVERT (date, sod.ModifiedDate) = *07/01/2005‘
查看上面查询的执行计划可以看出,这里进行的是聚集索引扫描,如图4-3所示。但
本来是可以进行聚集索引査找的。
面对这类问题时,可以对语句进行改写。
SELECT soh.SalesOrderlD , OrderDate , DueDate , ShipDate , Status , SubTotal ,
TaxAmt ,
Freight , TotalDue FROM S a l e s . S a le s O r d e r h e a d e r AS so h INNER JOIN S a le s . S a le sO rd e rD e ta il AS sod ON so h .S alesO rd erlD = so d .S alesO rd erlD WHERE s o d . M odifiedD ate >= * 2 0 0 5 -0 7 -0 1 0 0 :0 0 :0 0 .0 0 0 * AND s o d . M odifiedD ate < * 2 0 0 5 -0 7 -0 2 0 0 :0 0 :0 0 .0 0 0 *

另外,常见的非SARG查询还包括对where条件中的列使用一些如UPPER/LTRIM/ ISNULL之类的标量函数。对于这类情况,绝大部分情况下通过改写查询都能解决。

4 . 隐式转换
隐式转换(执行计划中会出现Implicit conversions)指一个查询的FROM/WHERE子句
中,用于关联或判断的列之间数据类型不相等,导致优化器需要根据数据类型的优先级高
低进行类型转换然后再优化、执行。由于SQL Server无法匹配不同类型的数据,所以需要 先将它们转换成相同类型再进行匹配。这个步骤发生在查询执行过程中。但是如果出现这
种情况,会导致查询转变成非SARG查询,从而出现类似上面介绍的问题。比如下面这个

查询:
SELECT p .FirstName , р . LastName , с. AccountNumber FROM Sales.Customer AS c INNER JOIN Person.Person AS p ON c.PersonlD = p.BusinessEntitylD
WHERE AccountNumber = N*AW00029594‘执行上面的语句,并查看实际执行计划中
的图标属性,如图4-5所示。

在图4-5中,加框部分就是查询需要把varchar类型隐式转换成nvarchar类型。解决这 类问题最好的方法是在设计过程中就先考虑数据类型,并且确保在where条件中变量、参 数、常量等都和数据列的类型一致。如果无法做到,可以考虑在传人where条件之前先进 行屋式数据类型转换。
5 . 参数嗅探
参数嗅探( Parameter sniffing)是 SQL Server创建针对存储过程、函数或者参数化查
询的执行计划时,根据传人的参数进行预估并生成(或重用)执行计划的一个功能。通常来
说,参数嗅探方式是比较好的功能,因为可以重用计划缓存。但是有些时候,针对一个查
询的第一次传参已经产生了一个执行计划,当后续传参时,由于存在对应参数的数据分布
等问题,导致原有的执行计划无法髙效响应请求,这时候就会出现参数嗅探问题。参数嗅
探仅出现在执行计划的编译或者重编译过程中。

来看看下面这个例子:
—创建存储过程
CREATE PROCEDURE user_GetCustomerShipDates
(
@ShipDateStart DATETIME , @ShipDateEnd DATETIME
)
AS
SELECT CustomerlD , SalesOrderNumber FROM Sales.SalesOrderHeader WHERE ShipDate BETWEEN @ShipDateStart AND @ShipDateEnd
GO
--创建非聚集索引,演示完毕后请删除
CREATE NONCLUSTERED INDEX IDX_ShipDate_ASC ON Sales.SalesOrderHeader (ShipDate)
GO
— 清空缓存
DBCC FREEPROCCACHE
EXEC user_GetCustomerShipDates * 2005/07/08 *, *2008/01/01‘
EXEC user_GetCustomerShipDates * 2005/07/10‘, 12005/07/20 *

从 图 4-6可以看到,虽然在ShipDate上有索引,但还是进行的聚集索引扫描。这是因 为在第一个存储过程的参数中,查询条件的时间范围几乎包括了全表的所有时间,另外由
于非聚集索引没有覆盖查询(在第6 章介绍),因此使用了聚集索引扫描操作。而第二个存
储过程仍然会沿用上面的执行计划,但是实际上它只需要查询十天的数据,按理是不应该
存在扫描,可它还是进行了聚集索引扫描。现在把上面的存储过程顺序调换一下,注意先
清空计划缓存。
DBCC FREEPROCCACHE -清空计划缓存,避免原有执行计划对本例造成影响
EXEC user_GetCustomerShipDates ‘2005/07/10‘, ,2005/07/20‘
EXEC user_GetCustomerShipDates ‘2005/07/08‘, ‘2008/01/01‘

从图4-7可以看到,两个查询都使用了索引查找。如果打开SET STATISTICS IO/TIME
这两个配置,然后对比上面两次查询的CPU时间,会发现前者第一个查询的CPU时间远
大于第二个,而后者的第二个时间远大于第一个。这是因为对于范围比较大的那个参数区
间,CPU需要处理更多的数据。
对于参数嗅探问题,可以使用部分重编译、编译提示(OPTIMIZE FOR)等功能来避
免,更多的优化应该考虑数据和研究数据分布问题。

6 . 非参数化Ad-hoc查询
Ad-hoc称为即席查询,可以理解为没有使用存储过程、SP_ExeCUteSql或者其他方式强 制预定义SQL语句。这类查询会导致SQL Server每次都要检查是否有计划缓存可用于完全 匹配这些语句。在这类语句中,即使只有参数不同,都会导致CPU分别进行编译和优化。
而这将导致CPU的浪费(浪费在对本来可以重用的执行计划上),也会因为对Ad-hoc查询 分别存放执行计划(可能只会用一次)导致计划缓存空间的浪费。可以使用下面的计数器来
进行监控,看看是否存在这样的浪费。
□ SQL Server: SQL Statistics: SQL Compilations/Sec □ SQL Server: SQL Statistics: Auto-Param Attempts/Sec □ SQL Server: SQL Statistics: Failed Auto-Param/Sec 如果是非参数化的A d-hoc,即不带参数的A d-hoc,比如select * from tb where id =xxx
这类查询引起了问题,在 SQL Server 2008中,可以使用图4-8所 示 的 “高级”选项来对其 进行优化。
或者在数据库层面强制参数化。
ALTER DATABASE AdventureWorks SET PARAMETERIZATION FORCED

7 . 非必要的并行查询
并行操作会把一个査询分开到多个线程中执行,然后再合并到一起返回结果。当一个
査询的开销超过cost threshold for parallelism这个阈值时(默认为5 秒),就会检查是否有可
用 的 CPU用于支持并行操作,其中,并行度取决于max degree of parallelism的值。 但是 对于OLTP系统,并行操作往往是非必需的,过多的并行执行会加重CPU的负担。可以用
下面语句来检查是否存在并行操作的执行计划。
SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;
WITH XMLNAMESPACES
(DEFAULT ?http://schemas.microsoft.com/SQL Server/2004/07/showplan*) SELECT query_plan AS CompleteQueryPlan , n.value(?(@StatementText)[1]?, *VARCHAR(4000)*) AS StatementText , n.value(1 (QStatementOptmLevel) [1]*, ’VARCHAR(25) 1) AS StatementOptimizationLevel , n.value(*(QStatementSubTreeCost)[1]、 *VARCHAR(128)*) AS StatementSubTreeCost , n.query(?.‘) AS ParallelSubTreeXML , ecp.usecounts f ecp.size_in_bytes FROM sys.dm_exec_cached_plans AS ecp CROSS APPLY sys.dm_exec_query_plan(plan_handle) AS eqp CROSS APPLY query_
plan.nodes (?/ShowPlanXML/BatchSequence/Batch/Statements/StmtSimple‘) AS qn ( n ) WHERE n.query(*.*).exist(*//RelOp[@PhysicalOp=M Parallelism” ]‘) = 1
对于存在并行操作的査询,不建议马上降低并行度,应该优化查询,使其尽可能保持
在并行开销的阈值以内。CPU髙利用的情况可能会有很多,这里只给出几个常见的类型及
对应的处理方法,在后续的章节中会陆续进行进一步的描述。

原文地址:https://www.cnblogs.com/zhouwansheng/p/9248084.html

时间: 2024-08-30 00:33:54

4 .3 .4 常见高CPU利用率的原因的相关文章

MongoDB CPU 利用率高排查

MongoDB CPU 利用率高,怎么破? 经常有用户咨询「MongoDB CPU 利用率很高,都快跑满了」,应该怎么办? 遇到这个问题,99.9999% 的可能性是「用户使用上不合理导致」,本文主要介绍从应用的角度如何排查 MongoDB CPU 利用率高的问题 Step1: 分析数据库正在执行的请求 用户可以通过 Mongo Shell 连接,并执行 db.currentOp() 命令,能看到数据库当前正在执行的操作,如下是该命令的一个输出示例,标识一个正在执行的操作.重点关注几个字段 cl

Linux下如何查看高CPU占用率线程 LINUX CPU利用率计算

目录(?)[-] proc文件系统 proccpuinfo文件 procstat文件 procpidstat文件 procpidtasktidstat文件 系统中有关进程cpu使用率的常用命令 ps 命令 top命令 单核情况下Cpu使用率的计算 基本思想 总的Cpu使用率计算 计算方法 某一进程Cpu使用率的计算 计算方法 实验数据 某一线程Cpu使用率的计算 计算方法 实验数据 多核情况下cpu使用率的计算 实验一 描述 数据一 数据二 实验二 描述 数据一 数据二 主要问题 Java 系统

jstack命令定位java程序CPU利用率高的代码位置

高手是怎么使用jstack精确找到异常代码的(java程序CPU利用率高的情况) 请jstack神器来帮忙 本文介绍Linux环境下使用jstack定位问题的秘笈s1.[top命令]找到CPU利用率持续比较高的进程,获取[进程号],此处PID为 1289112891 s2.[ps p 12891 -L -o pcpu,pid,tid,time,tname,cmd 命令]找到上述进程中,CPU利用率比较高的[线程号TID](十进制数),此处为 12946ps p 12891 -L -o pcpu,

抓 TOP SQL 解决CPU利用率过高问题

--模拟CPU利用率过高的情况: SQL> select count(*) from  T_LTE_CARD_INFO ; COUNT(*) ---------- 3516598 SQL> select * from  T_LTE_CARD_INFO ; [[email protected] ~]$ top top - 11:10:20 up 19:31,  3 users,  load average: 0.17, 0.23, 0.14 Tasks: 187 total,   3 runni

erlang 调度器CPU利用率低排查

-问题起因 近期线上一组服务中,个别节点服务器CPU使用率很低,只有其他1/4.排除业务不均,曾怀疑是系统top统计错误,从Erlang调度器的利用率调查 找到通过erlang:statistics(scheduler_wall_time) 查看服务器CPU低的机器调度器实际的CPU利用率很高接近100%,而其他机器都不到30%. 分析不同业务服务,发现只有在node 中进程数采用调度器CPU利用低这个问题. -Whatsapp 案例 erlang方面能找到案例不多,幸运的发现whatsapp

CPU利用率异常的分析思路和方法交流探讨

CPU利用率异常的分析思路和方法交流探讨在生产运行当中,经常会遇到CPU利用率异常或者不符合预期的情况,此时,往往暗示着系统性能问题.那么究竟是核心应用的问题?是监控工具的问题?还是系统.硬件.网络层面的问题?在上线前的测试过程中,经常会遇到新版本应用的CPU占用率比旧版本高,那么到底是新增的或者变更的什么模块导致呢?面对这种情况,我们应该如何定位和诊断问题的根本原因? 本期专题讨论会分享采用什么样的分析思路.分析方法和分析工具进行CPU使用情况的分析:并帮助大家解答以下问题: 1. CPU利用

cpu利用率和cpu 队列

SIP的第四期结束了,因为控制策略的丰富,早先的的压力测试结果已经无法反映在高并发和高压力下SIP的运行状况,因此需要重新作压力测试.跟在测试人员后面做了快一周的压力测试,压力测试的报告也正式出炉,本来也就算是告一段落,但第二天测试人员说要修改报告,由于这次作压力测试的同学是第一次作,有一个指标没有注意,因此需要修改几个测试结果.那个没有注意的指标就是load average,他和我一样开始只是注意了CPU,内存的使用状况,而没有太注意这个指标,这个指标与他们通常的限制(10左右)有差别.重新测

shell脚本统计多个CPU利用率

本节主要内容:top命令统计CPU的利用率 一,问题分析 MySQL在Linux下是多线程的,而且只能将多个线程分布到一个CPU上.因此,使用小型服务器,或者PC SERVER,多个CPU利用率并不高.基本上有1~2个在使用. 本节分享下统计CPU的利用率的方法,供大家学习参考. 相关阅读:查看Linux系统资源占用(top.free.uptime)top命令显示内容的详细解释 二,shell脚本实现 1.输入 top  -bn1  (b控制输出格式为文本格式,非交互格式) [[email pr

常见的CPU架构

CPU架构从大的层面分两类--CISC.RISC. x86 CISC就是复杂指令集计算机,目前专指 x86 和 x86-64 两类 其中 x86 又叫 IA32,即 Intel Architecture 32(Intel32位架构),不管是Intel生产的 x86 CPU,还是AMD或者VIA生产的,都是 IA32,IA32 并非没有专利保护而是 AMD 和 VIA/Cyrix 通过交叉专利授权获得了 IA32 的使用权. x86-64 又叫 AMD64,它的 Intel 版本叫做 EM64T(