暂无图片
暂无图片
3
暂无图片
暂无图片
暂无图片

Oracle通过dump块定位行锁的数据行

背景

今天上午在查询行锁的事后发现v$lock的id1和id2,阻塞的和被阻塞的会话一样,这能说明什么?

既然是被阻塞了,那争用的应该是同一块数据,但是一个事务已经修改了,没提交数据块上还有前镜像的指针,另一个事务想要修改(这里应该修改不了那为什么id1和id2一样呢),应该是构造一致性读去读取这个地址吧?

这里计一个todo,先来看看怎么根据行锁定位到具体是哪一个表的行数据产生了行锁。

首先id1和id2其实是和 v$trasaction 的字段相对应的

id1=xidusn+xidslot(回滚段号+回滚槽号)

id2=xidsqn(回滚槽号的覆盖次数)

后面说计算,这三个记录在数据块的 ITL,相对应的还有被修改数据的前镜像uba(回滚段地址)

uba在v$trasaction也有记录,

uba=回滚块地址(文件号+块号)+ 回滚序列号 + 回滚记录号

总结一下就是当前事务的三个xid、四个uba 和上面一一对应记录在v$trasaction

select xidusn,xidslot,xidsqn,ubafil,ubablk,ubasqn,ubarec from v$transaction;

思路:事务记录在块的ITL,尝试根据v$trasaction的回滚段号和块号找到发生行锁的块地址。

环境

Oracle11g

SYS@orcl> select * from v$version; BANNER -------------------------------------------------------------------------------- Oracle Database 11g Enterprise Edition Release 11.2.0.4.0 - 64bit Production PL/SQL Release 11.2.0.4.0 - Production CORE 11.2.0.4.0 Production TNS for Linux: Version 11.2.0.4.0 - Production NLSRTL Version 11.2.0.4.0 - Production

模拟行锁

这里用本地的一个测试表demo01数据如下:

构造行锁,修改id=2的行数据id:2 name:test2 sex:男

接下来假装不知道是这里发生的阻塞,去找这一行数据

会话一:

SYS@orcl> update demo01 set sex='男' where id=2; 1 row updated. SYS@orcl>

会话二

我们知道的情况下就好办了,直接找到数据块,dump下来

select rowid, dbms_rowid.rowid_relative_fno(rowid) rel_fno, dbms_rowid.rowid_block_number(rowid) blockno from demo01 where id = 2;

通过dbms_rowid.rowid_create直接定位

20241210补充信息:

--根据刘老师的提示又写了一条SQL,不用再dump那么费事了,再次感谢刘老师! --根据被锁住的表查找具体被锁住的行 WITH t1 AS ( SELECT c.sid, b.owner, b.OBJECT_NAME, b.OBJECT_TYPE, b.OBJECT_ID, c.ROW_WAIT_OBJ#, c.ROW_WAIT_FILE#, c.ROW_WAIT_BLOCK#, c.ROW_WAIT_ROW#, b.DATA_OBJECT_ID, a.XIDUSN, a.XIDSLOT, a.XIDSQN FROM v$locked_object a JOIN dba_objects b ON a.OBJECT_ID = b.OBJECT_ID JOIN v$session c ON a.session_id = c.sid WHERE b.OBJECT_NAME = 'DEMO01' and ROW_WAIT_OBJ#<>-1 ) SELECT * FROM sys.DEMO01 WHERE ROWID IN ( SELECT dbms_rowid.rowid_create( 1, t1.DATA_OBJECT_ID, t1.ROW_WAIT_FILE#, t1.ROW_WAIT_BLOCK#, t1.ROW_WAIT_ROW# ) AS create_rowid FROM t1 );

实验

查找行锁信息

select sn.username, sn.LAST_CALL_ET, sn.COMMAND, sn.STATUS, m.sid, sn.serial#, sn.sql_id, m.type, decode(m.lmode, 0, 'none', 1, 'null', 2, 'rowshare', 3, 'rowexcl.', 4, 'share', 5, 'srowexcl.', 6, 'exclusive', lmode, ltrim(to_char(lmode, '990'))) lmode, decode(m.request, 0, 'none', 1, 'null', 2, 'rowshare', 3, 'rowexcl.', 4, 'share', 5, 'srowexcl.', 6, 'exclusive', request, ltrim(to_char(m.request, '990'))) request, m.id1, m.id2 from v$session sn, v$lock m where (sn.sid = m.sid and m.request != 0) --存在锁请求,即被阻塞 or (sn.sid = m.sid --不存在锁请求,但是锁定的对象被其他会话请求锁定 and m.request = 0 and lmode != 4 and (id1, id2) in (select s.id1, s.id2 from v$lock s where request != 0 and s.id1 = m.id1 and s.id2 = m.id2)) order by id1, id2, m.request;

可以看到sid=427的会话在2024-12-05 10:50:42登录一直处于INACTIVE, LAST_CALL_ET:9772s,发生阻塞的数据在demo01

根据阻塞会话的 sid 就能找到v$trasaction ,有xid信息,undo 信息ubafile ubablk

select s.sid , s.serial# , s.username , t.addr taddr , s.saddr ses_addr , t.used_ublk , t.used_urec -- , t.start_time , to_char(t.flag, 'XXXXXXXX') "0xFLAG" , t.status||CASE WHEN BITAND(t.flag,128) = 128 THEN ' ROLLING BACK' END status , t.start_date , XIDUSN , XIDSLOT , XIDSQN , t.xid , t.prv_xid , t.ptx_xid from v$session s , v$transaction t where s.saddr = t.ses_addr and sid=427;

id2=2070=xidsqn

id1=262163转成十六进制4 0013

高位4=xidusn,低位0013(十六进制)=xidslot=19(十进制)

又可以得到uba

select * from v$transaction where xidusn=4 and xidslot=19 and xidsqn=2070;

uba=回滚块地址(文件号+块号)+ 回滚序列号 + 回滚记录号

3号文件 4364块

dump undo块

SYS@orcl> alter system dump datafile 3 block 4364; System altered. SYS@orcl> exec get_trace_name /u01/app/oracle/diag/rdbms/orcl/orcl/trace\orcl_ora_5296.trc PL/SQL procedure successfully completed.

dump undo 段头

根据上面的xid与v$rollname的usn关联得到段头

SYS@orcl> select name from v$rollname where usn=4; NAME ------------------------------ _SYSSMU4_1254879796$

dump undo段头

SYS@orcl> ALTER SYSTEM DUMP UNDO BLOCK '_SYSSMU4_1254879796$' XID 4 19 2070; System altered. SYS@orcl> exec get_trace_name /u01/app/oracle/diag/rdbms/orcl/orcl/trace\orcl_ora_1484.trc PL/SQL procedure successfully completed.

–bdba 表示block address hdba 代表sgment header address

–当中 bdba 表示file 4,block 94,449 , hdba 表示file 4。block 94,448

block address:

sgment header address:

找到块地址之后就可以dump数据块了

dump 数据块 <<找到行锁的数据

SYS@orcl> alter system dump datafile 1 block 94449; System altered. SYS@orcl> SYS@orcl> exec get_trace_name /u01/app/oracle/diag/rdbms/orcl/orcl/trace\orcl_ora_6708.trc PL/SQL procedure successfully completed. SYS@orcl>

得到dump的块,想得到被锁住的行数据 一是在数据区找到真正的数据(还没学会bbed)二是在尾区找,我们来找一下:

dump的一段内容:

block_row_dump:

tab 0, row 0, @0x1c57 ––第一个表第一行的位置 ,定义了该表在行索引中的起始插槽号

tl: 16 fb: --H-FL-- lb: 0x0 cc: 3 –行头,tl 表示行的总长度(total length)这里是 16 个字节。

–fb 表示行的标志字节(flag byte),用来标识行的状态。D表示被删除,这个之前做过实验Oracle delete删除数据是否为逻辑删除、新插入数据占用的数据块位置实验 - 墨天轮

–cc:3 -表示有列数,这个表有三个字段

col 0: [ 2] c1 02 –第一行的第一个字段长度和值

–表示第 0 列的内容是一个长度为 2 的值,十六进制为 c1 02

col 1: [ 5] 74 65 73 74 31 –同理第一行的第二个字段长度和值

--表示第 1 列的内容是一个长度为 5 的值,十六进制为 74 65 73 74 31

col 2: [ 3] e5 a5 b3

tab 0, row 1, @0x1c67

tl: 16 fb: --H-FL– lb: 0x2 cc: 3 <<< ––lb: 0x2 说明事物在该数据行上的锁还没清除,并且该锁指向 02 号事物槽如下图。

col 0: [ 2] c1 03

col 1: [ 5] 74 65 73 74 32

col 2: [ 3] e7 94 b7

通过UTL_RAW转化一下,就可以看到被锁住的表的行数据了

有意思,非常有意思,实验室参考下面的文章做的,刚吸收一点点,我在去学习一下。

参考:

oracle回滚机制深入研究 - ldxsuanfa - 博客园

最后修改时间:2024-12-10 19:18:44
「喜欢这篇文章,您的关注和赞赏是给作者最好的鼓励」
关注作者
【版权声明】本文为墨天轮用户原创内容,转载时必须标注文章的来源(墨天轮),文章链接,文章作者等基本信息,否则作者和墨天轮有权追究责任。如果您发现墨天轮中有涉嫌抄袭或者侵权的内容,欢迎发送邮件至:contact@modb.pro进行举报,并提供相关证据,一经查实,墨天轮将立刻删除相关内容。

评论