从数据库系统DBMS概念提出开始,并行和串行一直是数据库系统设计者不断权衡的一个焦点问题。
1、从串并行到行级锁
并行化是使DBMS支持多用户同时访问数据库,提高整体效率的关键技术手段。不同用户可以同时向DBMS提交执行数据库操作语句。但是,一些场景下,对一些资源对象无控制的并行,是会引起一些问题,影响数据库完整性等一些基本原则。在这种情况下,DBMS势必会引入串行化机制,来保护特定的对象资源。于是Enqueue(Lock)和Latch等锁对象就成为保护串行化访问资源的重要手段。
作为当今企业级DBMS主流的Oracle,其成功很大一部分因素在于早期的系统架构设计和一些关键核心技术方案,如redo、行级锁。这些在当时处在领先的理念技术,奠定了Oracle今天的市场和行业地位。
Oracle是一个典型的行级锁系统。就是说,当我们进行DML操作的时候,操作会话只会将被操作记录锁定住。操作会话是不会阻塞其他会话对该数据表进行的DML操作的。这种机制就大大提升了会话间事务并发的性能。
SQL> select * from v$version;
BANNER
----------------------------------------------------------------
Oracle Database 10g Enterprise Edition Release 10.2.0.1.0 - Prod
PL/SQL Release 10.2.0.1.0 - Production
CORE 10.2.0.1.0 Production
TNS for 32-bit Windows: Version 10.2.0.1.0 - Production
NLSRTL Version 10.2.0.1.0 – Production
--实验数据表
SQL> select * from t;
ID NA
---------- ----------
1 Record 1
2 Record 2
--在session1中
SQL> select sid from v$mystat where rownum<2;
SID
----------
144
SQL> update t set na='dfs' where id=1;
1 row updated
(此时事务并没有提交……)
--开启第二个会话
SQL> select sid from v$mystat where rownum<2;
SID
----------
151
SQL> update t set na='df' where id=2;
1 row updated
就普通的DML(insert, update, delete)操作而言,Oracle会加设两个锁定机制。首先是数据表级别的TM共享锁,防止在进行事务操作的时候,出现数据对象的DDL操作,修改数据表结构。同时,对指定的数据行使用一个独占的TX锁定。这样就保证了在进行DML操作的时候,既可以保证数据完整性要求,又可以最大程度的满足多会话并发的要求。
那么,我们在进行普通DML操作的时候,有哪些情况下,两个会话会出现阻塞情况。笔者总结常见的有如下几种。
2、常见DML阻塞
ü 修改相同记录引起的阻塞
显而易见的情况。如果会话A在对一条记录进行修改,事务未提交。同时会话B启动事务要求对相同记录进行修改。这个时候,会出现阻塞现象。
--会话A
SQL> select sid from v$mystat where rownum<2;
SID
----------
151
SQL> update t set na=null where id=1;
1 row updated
--此时会话B
SQL> select sid from v$mystat where rownum<2;
SID
----------
149
SQL> update t set na='df' where id=1;
(会话Hang住)
此时,如果我们观察两个会话的锁状态,可以看出问题所在。
SQL> select sid,type,id1,id2,lmode,request,block from v$lock where sid=151 or sid=149 order by sid;
SID TYPE ID1 ID2 LMODE REQUEST BLOCK
---------- ---- ---------- ---------- ---------- ---------- ----------
149 TM 54736 0 3 0 0
149 TX 131080 1251 0 6 0
151 TX 131080 1251 6 0 1
151 TM 54736 0 3 0 0
两个会话都试图获取到资源(131080, 1251)的独占权。该表示的是Undo段的地址空间位置,对应的是记录前镜像的保存。
ü 主键列DML变化引起阻塞
主键primary key表示的是非空和唯一两层约束保证。如果我们的DML操作涉及到主键列,如对主键列进行添加、修改和删除,可能就会引起并发操作阻塞的情况。
--添加数据主键约束
SQL> alter table t add constraint pk_t primary key (id);
Table altered
SQL> select * from t;
ID NA
---------- ----------
1 dfs
2 df
如果此时,一个会话发起了修改某行主键列的操作。另一个会话就可能不会允许进行某些针对主键列的操作,即使是相同数据行。
--第一会话中
SQL> select sid from v$mystat where rownum<2;
SID
----------
151
SQL> update t set id=3 where id=1;
1 row updated
--在会话二中(sid=149)
SQL> update t set id=4 where id=2;
1 row updated
SQL> rollback;
Rollback complete
SQL> update t set id=1 where id=2;
(阻塞)
SQL> update t set id=3 where id=2;
(阻塞)
从效果看,如果我们对主键列进行一个事务,将主键列取值发生可能的变化。那么,即使这个事务没有提交,其他会话在涉及到对该主键列的取值时,如果使用到了可能的变化值,会话时会被block的。
此时锁定情况如下:
SQL> select sid,type,id1,id2,lmode,request,block from v$lock where sid=151 or sid=149 order by sid;
SID TYPE ID1 ID2 LMODE REQUEST BLOCK
---------- ---- ---------- ---------- ---------- ---------- ----------
149 TX 458778 1293 0 4 0
149 TM 54736 0 3 0 0
149 TX 196650 1250 6 0 0
151 TX 458778 1293 6 0 1
151 TM 54736 0 3 0 0
同一般的锁定情况,我们发现了一些差异。第二个会话(sid=149)要求以lmode=4的方式获取事务段锁,被阻塞。
从道理上分析,Oracle这样做也是有其“为难之处”。默认情况下,Oracle对DML操作的约束检查是在操作进行时,而非commit时检查。当一个主键列从值A变化为B的时候,Oracle接收到了另一会话事务请求,要求将一个行主键列变为A。Oracle如果接受了第二会话的要求,那么第一会话rollback的时候就违反约束。如果Oracle拒绝了第二个会话的要求,那么第一会话commit的时候就无法处理了。两难情况下的Oracle,只能选择block第二个会话。
上面的两种情况是比较常见的,那么我们下篇介绍其他几种可能的block情况。
来自 “ ITPUB博客 ” ,链接:http://blog.itpub.net/17203031/viewspace-715796/,如需转载,请注明出处,否则将追究法律责任。
转载于:http://blog.itpub.net/17203031/viewspace-715796/