2017-08-09 DBA日记,并发高频执行SQL带来的思考

目的(Why)

深入理解当高频执行SQL时,oracle所发生的等待事件,并为此制定解决方案。

执行人员(Who)

ORACLE DBA

运行环境(Where)

  • database : oracle 11.2.0.3 + ASM +SSD # 当然是测试环境。
  • OS:IBM AIX 7.1
  • 模拟工具:在上一篇提到的使用python自主开发的一款并发工具。

模拟场景(What)

模拟30个用户,并发调用一个存储过程,该存储过程每调用一次就循环执行insert语句50W次.

模拟结果

  1. 当insert的目标表,没有索引时,主要的等待事件为cursor pin s
  2. 当insert的目标表,有索引时,等待事件如下:
    • cursor pin s
    • latch: cache buffers chains
    • buffer busy waits

结论

  1. cursor pin s
    • 官方解释: session waits for "cursor: pin S" when it wants a specific mutex in S (share) mode on a specific cursor and there is no concurrent X holder but it could not acquire that mutex immediately. This may seem a little strange as one might question why there should be any form of wait to get a mutex which has no session holding it in an incompatible mode. The reason for the wait is that in order to acquire the mutex in S mode (or release it) the session has to increment (or decrement) the mutex reference count and this requires an exclusive atomic update to the mutex structure itself. If there are concurrent sessions trying to make such an update to the mutex then only one session can actually increment (or decrement) the reference count at a time. A wait on "cursor: pin S" thus occurs if a session cannot make that atomic change immediately due to other concurrent requests. Mutexes are local to the current instance in RAC environments
    • 大概的意思是,session在用mutex以share方式锁定一个没有被加上独占锁的游标时,出现等待,按道理不应该是这样的,原来是因为,session在用mutex加锁前,要先更新mutex结构中的计数器,如果这时mutex的计数器,被另一个session锁定,则出现等待。
    • 理解完这个等待事件后,大概知道原因了,mutex是一个最轻量级的锁,按理来说操作应该很快的,估计在毫秒以下的,但是我在使用30个并发会话,调用loop来循环插入,这时候的并发请求(请求执行sql语句)时间,估计也达到毫秒以下,并且是在执行同一条SQL主句(绑定变量),所以30个并发会话,都会同对同一个cursor加share lock,都要调用同一个mutex,而此时cpu的使用率明显上升到60%左右,cpu能力下降,mutex更新计数器的操作就会变慢,cursor pin s就变成主要等待事件。(当然也有一个原因是采用SSD后,IO性能提升,logfile sync事件就减少了)
  2. latch: cache buffers chains,这个等待事件其实比较常见,在并发执行select时也会出现的,但是这次是在insert时出现的,可能的原因如下:
    • 在insert完后,新增了index的关键字值,这时index需要重排序,为了不影响排序结果,估计这时会所索引的所有数据块锁定,进行排序,一般情况下,这个排序应该也是很快完成的,但是这个场景的特点,并发请求数大(大于CPU数量),请求速度快(无须再建立连接,直接使用share sql cursor,ssd),所以此时目标表,数据量大的话,就算排序时间不变的情况下,其它会话会由于不能进行排序,也会出现这个等待事件。
  3. buffer busy waits,热块,常见事件,因为insert到表段及索引段上,都会引发这个事件。这里不特别说了。

解决方案

  1. 管理上,严控这种使用loop/while/for等循环结构的语句,在并发场景下,高频执行SQL语句。
  2. 监控上,监控活动会话数,以及每秒执行sql语句数。
  3. 优化,对于发现的SQL语句进行优化。

影响

占用大量的CPU资源,主要是在解释sql及索引排序时,如果CPU处理能力不足,数据库就会崩掉。

你可能感兴趣的:(ORACLE,DBA)