More Related Content Similar to Enqueue Lock介绍.ppt Similar to Enqueue Lock介绍.ppt (20) More from james tong (10) Enqueue Lock介绍.ppt5. Enqueue Lock 模式 模式 内部编号 模式值 描述 ( 以 DML 为例来说明 ) Null KSQMNull 1 Null 模式 , 不妨碍任何并发访问 , 主要用来作为 Cache Invalidate 的通知机制存在 SS KSQMSS 2 SubShare 模式 , 使用共享模式锁住一条记录 SX KSQMSX 3 SubExclusive 模式 , 使用独占模式锁住一条记录 S KSQMS 4 共享模式 SSX KSQMSSX 5 Share,SubExclusive, 对表持有共享锁 , 对其中的记录持独占模式 X KSQMX 6 Exclusive 模式 , 对全表持独占模式 6. Enqueue 模式兼容性 请求 / 占用 Null SS SX S SSX X Null Yes Yes Yes Yes Yes Yes SS Yes Yes Yes Yes Yes No SX Yes Yes Yes No No No S Yes Yes No Yes No No SSX Yes Yes No No No No X Yes No No No No No Editor's Notes 其他锁的类型 , 可参考 www.akadia.com/download/documents/session_ wait _ events .pdf 如果数据库版本为 11g 及以上 , 可以查询试图 v$lock_type 来得到 . Enqueue resource 结构由参数 enqueue_resources 确定 , 此值为一个初始值 , 其内容可通过 x$ksqrs (Kernel Service enQueue ReSource) 或者 v$resource 来查询 Enqueue lock 结构由隐含参数 _enqueue_locks 确定 , 此值在系统启动后不可更改 , 其内容可通过 x$ksqlk (Kernel Service enQueue LocK) 或 v$enqueue_lock 来查询 . Enqueue Resource 的资源结构由 Latch “enqueue hash chain” 来控制访问 . Enqueue Lock 的锁结构由 Latch “enqueues” 来控制访问 这两种资源的使用情况以及数量限制可通过查询 v$resource_limit 来获得 . Hash Bucket 的数量由参数 _enqueue_hash 控制 , 默认根据文件数 ,session 数据计算而来 . _enqueue_hash = 45 + 2 * ( PROCESSES + trunc(PROCESSES/10) ) 摘自 Steve Adams (Oracle 8i Internal Service,Page 50). 管理此 Hash Chain 的 Latch 为 enqueue hash chains,child latch 的数量由参数 _enqueue_hash_chain_latches 控制 , 默认值为 CPU 个数 操作 Enqueue Resource 都需要获取 enqueue hash chains latch. 操作 Enqueue Lock 都需要获取 enqueues latch 在释放完毕 Enqueue Lock 之后 , 如果有 converter , 则先通知 converter, 否则通知最早等待的那个 waiter. 我自己测试一般都是 Alter session set events ‘10704 trace name context forever , level 10’; 内容摘自 www.dbthink.com/?p=452 相关过程我自己做了测试 . 下面是持有锁的时间顺序 Lock table in SubShare mode Lock table in Share mode (very short time if not been blocked by others) Lock table in subShare mode Processing index rebuild Lock table in Share mode (very short time if not been blocked by others) Lock journal table in Exclusive mode (drop the journal table) select * from v$lock where sid in (10,14); ADDR KADDR SID TYPE ID1 ID2 LMODE REQUEST CTIME BLOCK 173D44A8 173D45B4 10 TX 262174 5398 6 0 37 1 17377074 17377088 10 TM 6279 0 3 0 37 0 173770F8 1737710C 14 TM 6279 0 3 0 22 0 17AE7288 17AE7298 14 TX 262174 5398 0 6 22 0 select sid,seq#,event,p1text,p1raw,p2text,p2,p3text,p3 from v$session_wait where sid in (14); SID SEQ# EVENT P1TEXT P1RAW P2TEXT P2 P3TEXT P3 14 17112 enqueue name|mode 54580006 id1 262174 id2 5398 select * from v$lock where sid in (10,14) ADDR KADDR SID TYPE ID1 ID2 LMODE REQUEST CTIME BLOCK 173D44A8 173D45B4 10 TX 589835 6969 6 0 16 1 17377074 17377088 10 TM 6279 0 3 0 16 0 173ADA20 173ADB2C 14 TX 196633 6878 6 0 10 0 173770F8 1737710C 14 TM 6279 0 3 0 10 0 17AE7288 17AE7298 14 TX 589835 6969 0 4 10 0 select sid,seq#,event,p1text,p1raw,p2text,p2,p3text,p3 from v$session_wait where sid in (14); SID SEQ# EVENT P1TEXT P1RAW P2TEXT P2 P3TEXT P3 14 17225 enqueue name|mode 54580004 id1 589835 id2 6969 创建一个 maxtrans 为 2 的表 , 表上的最小事务槽数量是 2 create table james_itl (id number,value varchar2(20)) maxtrans 2; 2. 往表中插入一定量的数据 , 找到 3 条位于同一 block 的记录 .( 比如 id 为 1,2,3 的三条记录 ) select rownum,dbms_random.string('l',15) from dual connect by level <= 1e3; select dbms_rowid.rowid_block_number(rowid) block_no,id,value from james_itl where rownum <= 5; BLOCK_NO ID VALUE 4701 1 dycxkqfjwnfmjcn 4701 2 irujlsgaesqsifx 4701 3 iujdkpwocphgewc 4701 4 clxxlwytqxvoufq 4701 5 oodfrpbgqpxybnh 3. 在三个不同的 session 分别更新这 3 条记录 session 1 Update james_itl set value = ‘test 1’ where id =1; Session 2 Update james_itl set value = ‘test 2’ where id = 2; Session 3 Update james_itl set value = ‘test 3’ where id = 3; 4. 通过 v$lock,v$session_wait 检查锁的级别 select * from v$lock where sid in (10,13,14); ADDR KADDR SID TYPE ID1 ID2 LMODE REQUEST CTIME BLOCK 173D40CC 173D41D8 10 TX 196647 6879 6 0 58 1 17377074 17377088 10 TM 6391 0 3 0 58 0 1737717C 17377190 13 TM 6391 0 3 0 54 0 17AE7288 17AE7298 13 TX 196647 6879 0 4 50 0 173ADA20 173ADB2C 14 TX 393226 4744 6 0 56 0 173770F8 1737710C 14 TM 6391 0 3 0 56 0 select sid,seq#,event,p1text,p1raw,p2text,p2,nvl(p3text,'xx') p3text,p3 from v$session_wait where sid in (10,14,13); SID SEQ# EVENT P1TEXT P1RAW P2TEXT P2 P3TEXT P3 13 66 enqueue name|mode 54580004 id1 196647 id2 6879 10 35567 SQL*Net message from client driver id 42455100 #bytes 1 xx 0 14 17472 SQL*Net message from client driver id 42455100 #bytes 1 xx 0 测试方式 : 在一个 uniform size 较小 ( 例如 128k) 的表空间中创建一个行记录本身很大的表 . 在几个 Session 同时对此表做大批量的数据插入操作 . 检查 v$enqueue_stat 查看 hw enqueue 的发生情况 Create tablespace test_128k datafile ‘ +datadatafile est_128k01.dbf’ size 1024m Extent management local uniform size 128k; Create table james_128k (id number,col1 varchar2(4000),col2 varchar2(4000),col3 varchar2(4000),col4 varchar2(4000)) tablespace test_128k; 在几个 session 中同时执行下面的插入语句 . Insert into james_128k Select rownum id,dbms_random.string(‘l’,4000) col1, dbms_random.string(‘l’,4000) col2, dbms_random.string(‘l’,4000) col3, dbms_random.string(‘l’,4000) col4 From dual Connect by level <= 1e5; *1 select segment_id,segment_name from dba_rollback_segs; 在 session 1 中创建全局临时表 , 并执行 dml 插入部分数据到临时表中 create global temporary table james_to on commit preserve rows as select * from obj; 2. 在 session 2 中对此临时表分别执行插入 ,truncate 以及在此表上创建索引的操作 . 对应的锁等待如下所示 Insert into james_to select * from obj; ksqcmi: TM,18e0,0 mode=3 timeout=21474836 ksqcmi: returns 0 *** 2010-07-25 21:43:06.000 ksqcmi: TO,18e0,1 mode=3 timeout=21474836 ksqcmi: returns 0 对此表执行 drop 操作 *** 2010-07-25 21:44:08.000 ksqcmi: TO,18e0,1 mode=6 timeout=0 ksqcmi: returns 51 对此表执行创建索引操作 ksqcmi: TO,18e0,1 mode=4 timeout=0 ksqcmi: returns 51 select * from v$lock where sid in (13); ADDR KADDR SID TYPE ID1 ID2 LMODE REQUEST CTIME BLOCK 17AE7288 17AE7298 13 JQ 0 3 6 0 272 0 select * from dba_jobs_running; SID JOB FAILURES LAST_DATE LAST_SEC THIS_DATE THIS_SEC INSTANCE 13 3 07/25/2010 23:58:24 23:58:24 0