拨云见日—深入解析Oracle TX 行锁(上)

在刚刚过去不久的第七届数据技术嘉年华上,性能优化专家怀晓明老师进行了Oracle性能优化的主题分享。在他多年的优化生涯中,一直遵守的优化理念是,平衡是唯一的核心。我们整理了怀老师大会的演讲内容,今天一起来学习,如何在实践中应用这一理念并实现有效的性能优化。

演讲实录

优化的核心思想是平衡。在数据库的运行中,平衡取决于三个方面:

需求:指的是要做什么;

资源:是系统中所能提供的内容;

实现:指的是为了满足需求,应该如何利用提供的资源。

只有三者达到平衡,系统才能够高效地运行。

今天的内容将会通过Oracle 中一个很具体的等待事件 TX行锁来剖析数据库的平衡。

什么是TX行锁?

等待事件: enq: TX - row lock contention

enq代表的意思是enqueue,事实上代表的是入队这一个动作。

contention指的是争用,所以一般意义上的行锁,其实指的是行锁争用。

不管是在Oracle数据库还是其他关系型数据库,在修改一条记录的时候一定会产生行锁。其目的是为了保证数据的一致性,如果行锁长久不能得到释放,当其他进程想要使用的时候,就会产生争用。这种情况一般发生在先行的会话事务没有结束的时候。

TX行锁发生的常见场景:

1、当前会话要更新或删除的记录,已经被其他会话更新或删除。

2、对于表上有唯一索引的情况,多个会话插入或更新为相同的键值。

3、对于表上有位图索引的情况,多个会话即使更新不同记录,只要这些记录在位图索引上的键值相同,也会产生行锁。

一般我们可能认为在发生行锁的时候,几个SQL的语句是一样的,事实上这种理解是错误的。我举一个简单的例子:

首先在表上找到job为manager的记录,有三条:

select empno from emp where job='MANAGER';

--显示7566/7698/ 7782 三条记录。

之后在会话1 将部门ID为10的员工的记录删除掉

sess1:delete from emp where deptno=10;

-- 7782/7839/ 7934 三条记录被删除,但并未提交。其中7782的记录刚好是job为manager的。

接下来在session2做一个delete的操作,此时就会被hang住。

sess2:delete from empwherejob='MANAGER';

那么hang的情况说明时候会结束呢?

--if sess 1 rollback, 7566/ 7698/7782将被删除
--if sess 1 commit,  7566/ 7698将被删除

也就是说只有资源被释放,系统才会解除TX行锁。

TX行锁的危害:会导致其他会话的相关业务操作hang住

1、业务操作长时间无法完成

用户投诉

2、会导致会话积压

数据库连接池逐渐被占满

  • 应用获取不到数据源无法创建新的数据库连接
  • 或操作系统CPU、内存资源逐渐耗尽,无法创建新的数据库连接

3、会导致产生其他争用,如bufferbusy wait, ITL contention等

TX行锁的解决方案:

1、先行会话需要结束事务(transaction):commit或者rollback

2、强制结束先行会话:kill session。

真实案例深入解析

来自双11的真实案例:双11早08:45,我方接到客户反映,在当天凌晨04:00~08:00,enq:TX - row lock contention等待严重。

当用户在投诉数据库严重的行锁问题的时候,我们首先会想到,在发生TX行锁时,由于资源久久得不到释放,系统中会话积压,导致DBtime会变得很高。

从图上看出,在问题发生的前两条开始采样,DBtime一直处于相对较低的状态,大概是100。在故障点,DBtime超过了800。

问题初现:从11月11日约00:00开始

高峰时刻:11月11日凌晨04:00达到峰值。

高峰值:该时刻DBTimes峰值为835.86,是该节点平日压力的十几倍,可见问题十分严重。

接下来我们查看了当时的AWR的报告。在AWR报告里面,我们首先要关注的是等待事件。我们看到其中TX行锁占用了大部分的等待时间,因此初步推断行锁就是导致故障的原因。

那么具体的行锁在什么地方呢?

通过top SQL查行锁的话,可能会比较困难。推荐大家通过segment部分进行查询。在segment模块,有一个专门针对行锁的统计, segment by row lock waits.从这个统计中我们看到,有一张命名为_manager_tp的表,占用了99%的行锁争用。

明确了争用对象以后,我们再来找对应的SQL语句。

在以耗时排名的top SQL 中,有一条SQL占比达到98%,这条SQL语句正在对_manager这张表进行update操作。但是我们之前看到的那张争用的表是_manager_tp, 跟这里查出来的manager不是同一张表。

原因是什么呢?

后经查证,MANAGER是指向表*MANAGER_TP的同义词。我们知道在运营商的环境中,他们很喜欢用同义词指向一张表。

因此,现在确认在top SQL里面涉及的对象和争用的segment的对象是匹配的。

接下来我们看一下从ASH分析出来的00:00 到08:00的趋势:

我们看到在整体的上升的趋势中,有一些点会产生向下的波动,向下的波动在行锁争用中是很常见的一种现象。当有一部分行锁被释放之后,被阻塞的量就会往下降。但是在持续的行锁阻塞中,虽然会有短暂的释放和缓解,但更多的会话会很快拥堵上来。

我们再对峰值期间的的行锁争用进行详细分析:

我们看到每一秒行锁争用的个数都达到了800+,只有在少数的时刻降到了几十。

因此到这一步,我们首先明确了分析方向:

该SQL自身导致的行锁,与其他无关

排除了存储不稳定可能导致SQL运行缓慢的可能性

第二条是因为在客户的机房环境下,经常会由于存储的不稳定导致应用SQL变慢。所以在故障发生的时候,也首先查看了操作系统的错误日志。

当我们确定了是某一条SQL导致的行锁,接下来我们对该SQL语句进行深入分析:

SQL全文如下:从SQL文本来看,对应到的应该是比较少的记录。

UPDATE *MANAGE
SET EXPIRE_DATE= SYSDATE
WHERE ACCESS_NUM = :1
AND IDENT_CODE_LEVEL= :2
AND IDENT_CODE_TYPE= :3

其执行计划如下:走的是索引范围扫。从TP_AN看到,并不是一个唯一索引。

相关的表和索引信息如下:

我们看到表有200w的记录,access_num为40w左右。因此平均每行的访问为6。

然后我们把SQL的AWR报告导出来一看,我们可以看到平均每次要处理7w多条记录,和6相比差别很大。这说明数据存在严重的倾斜。

因此我们做了一个查询,结果如下:

有些号码对应到十几万条记录,数据倾斜严重。

因此我们推测,发生故障是因为多会话在更新相同的access_number

深度分析:数据为什么会分布不均?

经过跟业务部沟通,发现:

每次用户申请凭证,表内就会记录一条凭证信息。

如果用户反复申请,表内对同一手机号就会记录多条信息。

问题为何产生?

一次就将表内一个手机号对应的所有记录的过期日期都更新为当前日期,是不合理的做法。

后来跟开发商进行沟通,得到以下结论:不是代码问题,就是设计问题

方案1:允许存在相同ACCESS_NUM对应多条记录的情况:正确的做法应该是只更新最新的记录,而早之前的记录不应该更新,因为其早已过期(过期日期比当前日期小)。
并将单表改为主子表关系,主表存最新的记录,子表存历史记录。

方案2:1个ACCESS_NUM在该表只应有一行记录的情况:应根据判断新进入该表的数据是否已经存在在表内,若是,则更新数据,若否,则插入数据。

因此开发商给出的方案:

后续得知,该问题不是第一次出现,曾经*MANAGER就是指向表*MANAGER的同义词!!!

我们根据前面的观点判断,在本案例当中,平衡三要素中的“实现”出现了问题。是由于开发设计不合理导致的行锁竞争。

原文发布时间为:2017-12-1

本文作者:怀晓明

本文来自合作伙伴“数据和云”,了解相关信息可以关注“数据和云”微信公众号

时间: 2024-08-03 09:42:05

拨云见日—深入解析Oracle TX 行锁(上)的相关文章

【赠书】拨云见日 - 深入解析Oracle TX行锁(下)

前文中我们详细介绍了TX行锁的概念,危害以及应对方案,并通过双11的一个经典案例进行了解读.今天我们分享另外一个跟TX行锁有关的案例. 案例描述 技术层面: 1.2017年某天,从当天大约10:30开始,A库上出现持续不断的严重行锁. 2.最初应用开发方的处理方式是不断杀会话(且并未通知我方),然而锁的问题一直持续到晚上还存在. 业务层面: 1.选号开户业务受到严重影响,成功开户的业务量仅为平常时刻的30%都不到. 2.业务群各地州市均有反馈该业务处理慢. 首先我们选取故障发生前1小时到处理前最

c#+oracle数据库行锁写法问题

问题描述 c#+oracle数据库行锁写法问题 请教各位高手: 我在c#+oracle,里面,想如此操作.当修改某一数据的前,先执行select行锁定,待修改完毕后再解锁.请问在不用存储过程的情况下,程序该如何写呢? 解决方案 最简单的是使用事务.http://www.cnblogs.com/yanghucheng/archive/2013/01/25/2876492.htmlhttp://happypigs.iteye.com/blog/1576282 解决方案二: 谢谢,能举个实际例子吗 解

全面解析oracle中的锁机制3

5.TX事务锁和 TM(DML enqueue)锁: TX锁:数据块的前面有一个开销空间(ITL),这里会存放一个块的事务列表,对于每一个锁定了块的事务,都会在这个事务列表中有一个条目.这个结构的大小有创建对象时的两个参数决定: INITRANS:初始分配的可容纳事务的大小,一般初始为2,可以说是事务槽. MAXTRANS:这个结构可以扩缩到的最大大小.它默认为255,在实际中,最小值为2.在Oracle10g 中,这个设置已经废弃了,所以不再使用.这个版本中的MAXTRANS 总是255.  

全面解析oracle中的锁机制4

7.enqueue: 什么是enqueue enqueue可以做名词,也可以做动词来解释. 做名词时,指的的是一种锁的类型,比如Tx enqueue. 做动词时,则是指将锁请求放入到请求队列的操作. 我们知道,lock是一种需要排队的锁实现机制,这和latch是不一样的,latch是一种轻量级的锁,是不需要排队得.Enqueue就是lock的排队机制的实现. lock是用来实现对于共享资源的并发访问的.如果两个session请求的lock是兼容的,则可以同时锁定资源,如果两个session请求的

全面解析oracle中的锁机制2

默认情况下 T@ora>create table t1 as select * from t ; Table created. Elapsed: 00:00:00.07 T@ora>select rowid,ora_rowscn,a from t1; ROWID                         ORA_ROWSCN          A ------------------                      ----------             --------

浅谈Oracle的行级锁

㈠ 单实例Oracle locking机制 locking机制的三大组成部分: ① resource structure Oracle对于每个需要"并发访问"的资源,都在SGA中用一个数据结构来描述它 这个结构叫resource structure 这个数据结构有三个成员:owner.waiter和converter 这是3个指针 指向由lock structure组成的链表的指针 其中,converter和waiter有些区别: 如果某个操作先后需要两种不同模式的锁,比如,先S,后X

解析oracle对select加锁的方法以及锁的查询_oracle

解析oracle对select加锁的方法以及锁的查询一.oracle对select加锁方法 复制代码 代码如下: create table test(a number,b number);insert into test values(1,2);insert into test values(3,4);insert into test values(8,9);commit;---session 1 模拟选中一个号码SQL> select * from test where a =1 for up

oracle等待事件6——行高速缓存上的等待事件

1.row cache lock oracle将数据子典信息存于SGA内的行高速缓冲区(或dictionary cache),行高速缓冲区位于共享池内,可以通过如下命令进行确认: SQL> select pool,name,bytes from v$sgastat where name='row cache'; POOL          NAME                                          BYTES ------------ --------------

Oracle中的锁(LOCK)机制

 本文结合示例简要的介绍了一下Oracle中锁的机制. 为了解决多用户环境下并发操作相同的资源而造成的错误修改数据的问题.单用户环境下不需要考虑锁,因为所有操作都是串行的.下面的文章简要的介绍了一下 锁的分类异常复杂,enqueue.latch.mutex等,都是为了解决并发存在的,自己也有些混乱,所以也不过多解释了.下面列举一些对于lock的要点内容. l 排他锁: 不允许相关的资源被共享.一个资源在一个时间点内只有一个事务能够获取该资源的排他锁,只有持有该锁的事务能够修改相关的资源, 其他想