收到一封告警邮件:

Load average on xxx_server reached critical threshold values - 169.5

Current Load Avg = 169.5

是个生产环境的,

于是立马登上服务器看下状况

top - 05:01:00 up 88 days, 5:03, 4 users, load average: 185.10, 200.94, 193.27
Tasks: 3442 total, 172 running, 3269 sleeping, 0 stopped, 1 zombie
Cpu(s): 96.3%us, 2.8%sy, 0.0%ni, 0.0%id, 0.0%wa, 0.0%hi, 0.9%si, 0.0%st
Mem: 527990848k total, 465240080k used, 62750768k free, 1593680k buffers
Swap: 31457276k total, 0k used, 31457276k free, 51934560k cached

PID USER PR NI VIRT RES SHR S %CPU %MEM TIME+ COMMAND
24225 oracle 20 0 256g 38m 29m R 68.8 0.0 16:31.12 oracle
34187 oracle 20 0 256g 37m 26m R 68.2 0.0 25:36.82 oracle
47581 oracle 20 0 256g 40m 27m R 68.2 0.0 226:48.02 oracle
35919 oracle 20 0 256g 44m 29m R 66.4 0.0 484:24.28 oracle
37934 oracle 20 0 256g 42m 29m R 64.8 0.0 460:41.09 oracle
24227 oracle 20 0 256g 43m 30m R 63.9 0.0 477:54.11 oracle
10826 oracle 20 0 256g 44m 30m R 63.0 0.0 518:04.92 oracle
64990 oracle 20 0 256g 148m 30m R 62.7 0.0 960:40.23 oracle
26610 oracle 20 0 256g 33m 26m R 60.2 0.0 5:10.04 oracle
31533 oracle 20 0 256g 37m 27m R 59.9 0.0 25:29.96 oracle
56682 oracle 20 0 256g 41m 30m R 59.3 0.0 443:13.79 oracle
39668 oracle 20 0 256g 37m 26m R 58.6 0.0 27:16.07 oracle

看了好几次,cpu的使用率一直是95%以上,前二十个都是oracle相关的进程,于是立马看下这些进程是什么sql在执行些什么

先随便找了一个cpu占比比较高的spid来看

select a.sid, a.serial#,a.username, a.osuser, b.spid,a.status

from v$session a, v$process b

where a.paddr= b.addr

and b.spid=40514

order by a.sid;

SID    SERIAL# USERNAME                       OSUSER                         SPID                     STATUS

---------- ---------- ------------------------------ ------------------------------ ------------------------ --------

2793        883 MSP_ALL_DML                    app                            40514                    ACTIVE

SQL_TEXT

----------------------------------------------------------------

UPDATE SYNC_PROCESSING_STATUS

SET STATUS_IND = :1 ,              RETRY_COUNT = :2 ,

ERROR_MSG = :3 ,              UPDATE_DATE = :4

WHERE SYNC_ID = :5              AND PROCESS_TYPE = :6

AND CREATE_DATE > sysdate-7

而后又找了一两个占比比较高的spid,同样也是在执行这个sql

再具体看下数据库有哪些正在执行的session

SID    SERIAL# SQL_ID        Run_in_sec OS_user                        MACHINE

---------- ---------- ------------- ---------- ------------------------------ ----------------------------------------------------------------

SQL_TEXT

-----------------------------------------------

MODULE                                                           EVENT

---------------------------------------------------------------- ----------------------------------------------------------------

6826      13187 0vqfhz794y0ys          7 app                            xxxx_appserver

UPDATE SYNC_PROCESSING_STATUS              SET STATUS_IND = :1 ,              RETRY_COUNT = :2 ,              ERROR_MSG = :3 ,              UPDATE_DATE = :4         WHERE SYNC_ID = :5              AND PROCESS_TYPE = :6              AND CREATE_DATE > sysdate-7

JDBC Thin Client                                                 latch free

10990      20293 0vqfhz794y0ys          7 app                            xxxxx_appserver

UPDATE SYNC_PROCESSING_STATUS              SET STATUS_IND = :1 ,              RETRY_COUNT = :2 ,              ERROR_MSG = :3 ,              UPDATE_DATE = :4         WHERE SYNC_ID = :5              AND PROCESS_TYPE = :6              AND CREATE_DATE > sysdate-7

JDBC Thin Client                                                 latch free

10994      18173 0vqfhz794y0ys          7 app                            xxxxx_appserver

UPDATE SYNC_PROCESSING_STATUS              SET STATUS_IND = :1 ,              RETRY_COUNT = :2 ,              ERROR_MSG = :3 ,              UPDATE_DATE = :4         WHERE SYNC_ID = :5              AND PROCESS_TYPE = :6              AND CREATE_DATE > sysdate-7

JDBC Thin Client                                                 latch free

6457      48363 0vqfhz794y0ys          7 app                            xxx_appserver

UPDATE SYNC_PROCESSING_STATUS              SET STATUS_IND = :1 ,              RETRY_COUNT = :2 ,              ERROR_MSG = :3 ,              UPDATE_DATE = :4         WHERE SYNC_ID = :5              AND PROCESS_TYPE = :6              AND CREATE_DATE > sysdate-7

JDBC Thin Client                                                 latch free

(output还有很多,这里省略)

看到了基本上全是在执行这个sql,active的session大概170个左右在执行这个。

于是跑去OEM看了下执行计划,

正在做全表扫描。

注意到了关键的一点,plan hash value有两个,于是猜测是不是执行计划变了导致的sql执行很慢,太多的session造成了热点快,从而造成了latch free的等待事件,从而cpu暴涨。

但是当时没有认证去分析latch的根源。

继续看了一下,

以前走的是index range scan,现在走的是full table scan。

并且关键的信息在于这张表的统计信息还是在2015年时候的,

execute dbms_stats.gather_table_stats(ownname=> 'xx', tabname=> 'SYNC_PROCESSING_STATUS', estimate_percent=> 5, cascade => true, degree => '8',NO_INVALIDATE => false);

在收集完统计信息之后,load正常了,cpu也降下去了。

==============ENDED====================================

问题就这样处理了,但是当时还是可以挖掘更多信息的,比如这个latch free的等待事件的分析,

这个事件会由很多的原因造成的,这里列举如下:

Shared pool library cache latch争用原因

Shared pool和library cache latch争用通常是由于硬分析引起。硬分析需要分配新的游标,或者将已经换出的游标重新执行。硬分析过多说明sql语句没有充分绑定变量。硬分析是代价十分昂贵的操作,在分析期间需要一直持有ibrary cache latch。

如果你的系统中存在大量的常量sql语句,当你将它们改为充分使用绑定变量后,对sharedpool latch和library cache latch的争用将会显著减少。更改sql语句,使用绑定变量,这通常需要修改应用程序。

Sharedpool latch争用原因二―― 过大的共享池

从oracle9i起,由于引入了多个子共享池的特性,过大的共享池不再是一种坏事。在9i之前,过大的共享池通常会引起sharedpool latch争用。共享池中可用内存分成不同的内存块(chunk),不同大小范围的块由不同的可用列表(freelist)来管理。在共享池中分配空间时,需要扫描可用列表,扫描期间,需要持有shared pool latch。过大的共享池会使得可用列表过长,从而使得sharedpool latch的持有时间变长。在高并发环境中,latch持有时间过长就可能造成latch争用(表现为较高的sleeps和misses值),尤其是大量使用常量sql的系统,对这样的系统,不要一味想着加大共享池,更重要的是想一想你为什么会需要保存这么多不能共享的语句到共享池中。

Library cache latch争用原因三――语句版本数过多

对于字符完全一致但是由于引用不同的对象而不能共享的sql语句,oracle使用多个子游标来指向该语句的不同版本。例如,系统中有三个名叫customer的表,但是属于不同的模式。则对于语句select * from customer,不同的模式执行该语句,语句字符上完全一样,其hash值完全一样,但是该语句无法共享,因为它引用的对象不同。所以会生成该语句的不同子版本。当一个sql语句有多个子版本时,oracle需要比较该语句的所有存在的子版本,在此期间需要持有librarycache latch,这样可能导致library cache latch争用。解决这种情况也很简单,在系统中,尽量不要使用相同的对象名。

Cache buffers chains latch

Cache buffers chains latch争用原因一 ―― 低效的sql语句

低效的sql语句是导致cache bufferschains latch争用的主要原因。在高并发系统中, atch free时间可能因此非常明显。典型的情况是,应用程序开启多个并发会话执行相同的低效sql,并且访问同样的数据集。

注意下面三点:

1.每次逻辑读都需要请求一次latch。

2.只有获得某个latch之后才会停止对该latch的不断请求。

3.在某个时刻,只有一个进程可以获得cache buffers chains latch,而该latch可能用于保护很多的数据块,其中的某些块可能正在被其他进程请求(当然,前面也已经提过,oracle9i允许只读性质的cache bufferschains latch共享)。

一般而言,较少的逻辑读意味着较少的latch请求,也就意味着较少的latch争用和更好的系统性能。所以,你应该找出导致cache bufferschains latch争用的低效sql语句,优化这些语句,尽量降低其逻辑读。那些buffers_get/executions比值较大的sql可能就是你需要调整的语句。

Cache buffers chains latch争用原因二―― 热点块

热点块是导致cache bufferschains latch争用的另外一个主要原因。当多个进程重复访问一个或多个由同一个cache buffers chains latch保护的块时会导致该问题。这通常是应用程序引起的。在这种情况下,增加cache bufferschains latch的个数对热点块导致的争用没有什么作用。因为数据块分布在哪个hash bucket和hash chain上是由块地址(dba:data block address)和hash bucket的个数决定的,和hash latch的个数没有关系。只要块地址和hash bucket数没有改变,这些热点块还是会分布在原来的hash bucket和hash chain上,还是由原来的hash latch保护,那么就还会对这些hash latch产生争用。除非系统中latch数目显著的增加(这样每个latch管理的hash bucket就会很少,甚至一个latch管理一个hash bucket,这样原来的热点块可能就会有其他的几个latch来管理,而不再需要争用原来的那个latch)。

解决这样的cache bufferschains latch争用,最好的方法是找出热点块。通过latch free等待事件的p1raw参数可以知道是否是因为热点块导致了latch争用。(在oracle10g中,cache buffers chains latch的相关等待事件不再是latchfree,而是cachebuffers chains)。P1raw参数是latch的地址。如果多个会话都在等待同一个latch地址,那么恭喜你遇到热点块问题了。

Cache buffers chains latch争用原因三―― 过长的hash chain

多个数据块可能分配到同一个hash bucket上。这些块组成一个链表(hash chain)。在一个大型系统中,一个hash bucket中可能有上百个数据块。从一个hash chain链表中搜索某个块,需要获得cache bufferschains latch,串行的进行。如果链表太长,使得latch持有时间相应增加,可能导致其他进程请求cache buffers chains latch失败。

-----------------------------------------------------------------------

如果要进一步分析的话,可以用如下sql来看下这个latch的具体信息

v$session的latch free等待事件p2就是指的latch的类型,然后用如下sql查看latch类型

SELECT LATCH#, NAME FROM V$LATCH WHERE LATCH# = 98;

SELECT * FROM V$LATCHHOLDER;

SQL>select latch#,name,gets,misses,sleeps from v$latch where name like 'cache buffer%';

在这个查询结果里我们可以看到记录了数据库启动以来的所有cahce buffer chains的latch的状况,gets表示总共有这么多次请求,misses表示请求失败的次数(加锁不成功),而sleeps 表示请求失败休眠的次数,通过sleeps我们可以大体知道数据库中latch的竞争是否严重,这也间接的表征了热点块的问题是否严重。由于v$latch是一个聚合信息,我们并不能获得哪些块可能存在频繁访问。那我们要来看另一个view信息,那就是v$latch_children,v$latch_children.addr记录的就是这个latch的地址。

SQL>select addr,LATCH#,CHILD#,gets,misses,sleeps from v$latch_children  where name = 'cache buffers chains' and rownum < 21;

主要分析latch free等待事件的就是这些v$latch,v$latchholder,v$latch_children,v$latchname,v$latch_parent这么几个视图,以后有时间再详细分析一下这几个视图的用法,以及从latch去确定某个block热点块的思路。

============================

当然关于这种执行计划突变的原因也有很多,本例是因为统计信息的原因,也有很多其他原因,比如比较常见的绑定变量窥探(数据量突变)等等,以后遇到了在具体分析。

在事后又大致看了一下,后续的sql执行计划也都走的是index range scan这个hash plan value为1107144300的执行计划了

SQL> SELECT DISTINCT sql_id, plan_hash_value
2 FROM dba_hist_sqlstat q
3 WHERE SNAP_ID BETWEEN 130811 AND 130812
AND q.sql_id='0vqfhz794y0ys'; 4

SQL_ID PLAN_HASH_VALUE
------------- ---------------
0vqfhz794y0ys 3910147552
0vqfhz794y0ys 1107144300

select SQL_ID,first_load_time,EXECUTIONS,LOADS,PARSE_CALLS from v$sqlarea where sql_id='0vqfhz794y0ys';

select  sql_id,plan_hash_value, child_number, executions, parse_calls, buffer_gets, is_bind_sensitive, is_bind_aware  from  v$sql  where  sql_id = '';

 

==========================ENDED===================================

cpu95%,查找问题sql的更多相关文章

  1. 查找bad sql的方法:

    --查找bad sql的方法: select * from (select buffer_gets, sql_text from v$sqlarea ; -- 执行次数多的SQL select sql ...

  2. SQLServer学习笔记<>sql的范围内查找,sql数据类型,字符串处理函数

    sql的范围内查找 (1)between.....and用法 通常情况下我们查找一个在某固定区域内的所有记录,可以采用>=,<=来写sql语句,例如:查找订单价格在1000到2000之间的 ...

  3. 多条件分页查找(SQL拼接方法)

    def startTime=params.startTime+" 00:00:00"  def endTime=params.endTime + " 23:59:59&q ...

  4. Laravel技巧集锦(16):使用DB::listen查找慢SQL

    1.AppServiceProvider.php中 \DB::listen(function ($query){ $sql = $query->sql; $bindings = $query-& ...

  5. 查找当前SQL Server下的Active Session正连接着哪个数据库

    今天碰到个事.原本想把数据库设为单用户模式然后把REMOVE FILE.没想到悲剧了.因为很多进程都是需要远程连接这个库,导致别的进程抢在我前面连接了这个数据库,反到我连不上了.想把数据库切回MULT ...

  6. SQL Server执行计划那些事儿(2)——查找和扫描

    接下来的文章是记录自己曾经的盲点,同时也透漏了自己的发展历程(可能发展也算不上,只能说是瞎混).当然,一些盲点也在工作和探究过程中慢慢有些眉目,现在也愿意发扬博客园的奉献精神,拿出来和大家分享一下. ...

  7. oracle中查找执行效率低下的SQL

    v$sqltext:存储的是完整的SQL,SQL被分割 v$sqlarea:存储的SQL 和一些相关的信息,比如累计的执行次数,逻辑读,物理读等统计信息(统计) v$sql:内存共享SQL区域中已经解 ...

  8. SQL Server Replication的分发服务器的快照文件夹位置查找

    SQL Server分发服务器配置中,需要配置快照文件夹(Snapshot Folder),用于存储发布的数据和架构文件的工作目录,那么如何查找当前SQL Server数据库服务器的分发服务器的快照文 ...

  9. 在 SQL Server 中查找活动的 SQL 连接

    在SQL Server中有几种方法可以找到活动的 SQL 连接.让我们看看一些使用 T-SQL 查询的简单快捷的方法. SP_WHO SP_WHO 是 SQL Server 内置的系统存储过程, 其他 ...

随机推荐

  1. Redis学习笔记(二)-key相关命令【转载】

    转自 Redis学习笔记(二)-key相关命令 - 点解 - 博客园http://www.cnblogs.com/leny/p/5638764.html Redis支持的各种数据类型包括string, ...

  2. linux通过history查看命令执行时间

    Linux的bash内部命令history就可以显示命令行的命令历史,默认环境执行 history 命令后,通常只会显示已执行命令的序号和命令本身.如果想要查看命令历史的时间戳,那么可以执行:# ex ...

  3. Memcached函数整理

    public bool Memcached::add ( string $key , mixed $value [, int $expiration ] )  向key中添加值,如果key存在,返回f ...

  4. zabbix企业应用之bind dns监控(转)

    继续介绍zabbix监控企业应用的实例,本次介绍zabbix监控dns,我监控的dns为bind 9.8.2,本dns为公网dns,是为了解决公司内网服务器自动化所需求的dns解析,比如目前的pupp ...

  5. android的m、mm、mmm编译命令的使用

    android的m.mm.mmm编译命令的使用   android源码目录下的build/envsetup.sh文件,描述编译的命令 - m:       Makes from the top of ...

  6. [Java]读取文件方法大全(转)

    [Java]读取文件方法大全   1.按字节读取文件内容2.按字符读取文件内容3.按行读取文件内容 4.随机读取文件内容 public class ReadFromFile {     /**     ...

  7. 新手常见的python报错及解决方案

    此篇文章整理新手编写代码常见的一些错误,有些错误是粗心的错误,但对于新手而已,会折腾很长时间才搞定,所以在此总结下我遇到的一些问题.希望帮助到刚入门的朋友们.后续会不断补充. 目录 1.NameErr ...

  8. log4j输出到指定日志文件

    log4j.properties: log4j.logger.myTest=DEBUG,console,FILE log4j.appender.console=org.apache.log4j.Con ...

  9. Qt5:Qt中一些函数功能介绍

    1  .setContentsMargins 该函数用于设置窗口客户区中,四周空白边框的尺寸 , 类似于 word 中的 页边距设置 2.canonical Path 返回文件路径的规范路径 , 也就 ...

  10. 设计模式笔记之三:Android DataBinding库(MVVM设计模式)

    本博客转自郭霖公众号:http://mp.weixin.qq.com/s?__biz=MzA5MzI3NjE2MA==&mid=2650236908&idx=1&sn=9e53 ...