Oracle 学习之性能优化(十)锁

锁(lock)是用于防止在访问相同的资源(包括用户对象、系统对象、内存、Oralce数据字典中的共享数据结构,最常见的是数据库表Table对象)时 ,事务之间的有害性 交互(存、取)的一种机制。

不同类型的锁,代表了当前用户是允许还是阻止其它用户对相同资源的同时存取,从而确保不破坏系统数据的完整性、一致性和并行性。

加锁是实现数据库并发控制的一个非常重要的技术。当事务在对某个数据对象进行操作前,先向系统发出请求,对其加锁。加锁后事务就对该数据对象有了一定的控制,在该事务释放锁之前,其他的事务不能对此数据对象进行更新操作。

锁的分类

  • DML锁:SELECT、INSERT、UPDATE、DELETE、MERGE操作
  • DDL锁:CREATE和ALTER语句操作
  • 内部锁和闩:Oracle使用这些锁来包含内部数据结构,例如:Oracle查询生成的执行计划,执行计划会保存在库缓存中,当使用这个执行计划时,会对其加一个闩(latch)

DML锁

用于确保一次只能一个人修改某行数据。而且你正常处理这个表时,别人不能删除这个表。

  1. TX锁,事务发起第一个修改时,会得到一个TX锁(事务锁),而且会一直持有这个事务,直到事务结束(COMMIT或者ROLLBACK)。事务中修改或者select for update的每一行都会指向该事务的TX锁。
  2. TM锁,用于确保在修改表内容时,表的结构不被改变。

下面举例说明

登录到scott用户,并确定session id

SQL> grant select any dictionary to scott;

Grant succeeded.

SQL> conn scott/tiger

SQL> select sid from v$mystat where rownum=1;

       SID
----------
	37

SQL>

另开启一个会话,监控锁的使用情况

SQL> set linesize 200
SQL> select * from v$lock where sid=37;

ADDR		 KADDR			 SID TY        ID1	  ID2	   LMODE    REQUEST	 CTIME	    BLOCK
---------------- ---------------- ---------- -- ---------- ---------- ---------- ---------- ---------- ----------
0000000090D8FC88 0000000090D8FCE0	  37 AE        100	    0	       4	  0	   481		0

SQL>

会话1执行更新操作

SQL> update emp set ename=initcap(ename);

14 rows updated.

会话2查看结果

SQL> /

ADDR		 KADDR			 SID TY        ID1	  ID2	   LMODE    REQUEST	 CTIME	    BLOCK
---------------- ---------------- ---------- -- ---------- ---------- ---------- ---------- ---------- ----------
0000000090D8FC88 0000000090D8FCE0	  37 AE        100	    0	       4	  0	   944		0
00007FF9EEDA4AB0 00007FF9EEDA4B10	  37 TM      87108	    0	       3	  0	     3		0
000000008F673658 000000008F6736D0	  37 TX     131074	  908	       6	  0	     3		0

多了一个事务锁,一个TM锁。

会话1中再执行另一个表的更新操作

SQL> update dept set dname=initcap(dname);

4 rows updated.

会话2查看结果

SQL> /

ADDR		 KADDR			 SID TY        ID1	  ID2	   LMODE    REQUEST	 CTIME	    BLOCK
---------------- ---------------- ---------- -- ---------- ---------- ---------- ---------- ---------- ----------
0000000090D8FC88 0000000090D8FCE0	  37 AE        100	    0	       4	  0	  1174		0
00007FF9EEDA7B58 00007FF9EEDA7BB8	  37 TM      87108	    0	       3	  0	   233		0
00007FF9EEDA7B58 00007FF9EEDA7BB8	  37 TM      87106	    0	       3	  0	    27		0
000000008F673658 000000008F6736D0	  37 TX     131074	  908	       6	  0	   233		0

事务锁没有变,但是又多了一个TM锁。

对于TM锁来说,id1的值是对象的ID

SQL> COL OBJECT_NAME FOR A30
SQL> select OBJECT_NAME,OBJECT_ID from dba_objects where owner=‘SCOTT‘ AND OBJECT_NAME IN (‘DEPT‘,‘EMP‘);

OBJECT_NAME			OBJECT_ID
------------------------------ ----------
DEPT				    87106
EMP				    87108

对于TX锁,id1是通过事务id转换来的。

我们先查看下事务的相关信息

SQL> SELECT addr,xidusn,xidslot,xidsqn FROM V$TRANSACTION;

ADDR		     XIDUSN    XIDSLOT	   XIDSQN
---------------- ---------- ---------- ----------
000000008F673658	  2	     2	      908

ADDR与TX锁的ADDR对应,XIDUSN表示回滚段编号,XIDSLOT表示事务表上的编号,XIDSQN表示sequence(覆盖次数)

TX锁的id1的值等于XIDUSN*power(2,16)+XIDSLOT

SQL> select 2*power(2,16)+2 from dual;

2*POWER(2,16)+2
---------------
	 131074

事务表、回滚块、事务槽 三者之间的关系如下:

对于TX锁,并没有一个视图能提供事务修改了哪些行。行锁的信息是保存在数据块中的。

下面我们将dept的数据块dump出,查看块的详细信息

SQL> select dbms_rowid.rowid_relative_fno(rowid) fno,dbms_rowid.rowid_block_number(rowid) bno from dept;

       FNO	  BNO
---------- ----------
	 4	  135
	 4	  135
	 4	  135
	 4	  135

只占用了一个数据块,将该块dump

SQL> alter system dump datafile 4 block 135;

System altered.

SQL> SELECT    d.VALUE
       || ‘/‘
       || LOWER (RTRIM (i.instance, CHR (0)))
       || ‘_ora_‘
       || p.spid
       || ‘.trc‘
          trace_file_name
  FROM (SELECT p.spid
          FROM v$mystat m, v$session s, v$process p
         WHERE m.statistic  2    3    4    5    6    7    8    9   10  # = 1 AND s.sid = m.sid AND p.addr = s.paddr) p,
       (SELECT t.instance
          FROM v$thread t, v$parameter v
         WHERE     v.name = ‘thread‘
               AND (v.VALUE = 0 OR t.thread# = TO_NUMBER (v.VALUE))) i,
       (SELECT VALUE
           11   12   13   14   15   16  FROM v$parameter
         WHERE name = ‘user_dump_dest‘) d;    17  

TRACE_FILE_NAME
--------------------------------------------------------------------------------
/u01/app/oracle/diag/rdbms/orcl/orcl/trace/orcl_ora_5593.trc

查看trace文件

Block header dump:  0x01000087
 Object id on Block? Y
 seg/obj: 0x15442  csc: 0x00.fab7a  itc: 2  flg: E  typ: 1 - DATA
     brn: 0  bdba: 0x1000080 ver: 0x01 opc: 0
     inc: 0  exflg: 0
 
 Itl           Xid                  Uba         Flag  Lck        Scn/Fsc
0x01   0x0009.002.00000364  0x00c167b0.009a.2e  C---    0  scn 0x0000.000e0ef0
0x02   0x0002.002.0000038c  0x00c00591.0088.26  ----    4  fsc 0x0000.00000000
bdba: 0x01000087
data_block_dump,data header at 0x7f23e518ea64
===============
tsiz: 0x1f98
hsiz: 0x1a
pbl: 0x7f23e518ea64
     76543210
flag=--------
ntab=1
nrow=4
frre=-1
fsbo=0x1a
fseo=0x1f3c
avsp=0x1f22
tosp=0x1f22
0xe:pti[0]	nrow=4	offs=0
0x12:pri[0]	offs=0x1f7e
0x14:pri[1]	offs=0x1f68
0x16:pri[2]	offs=0x1f54
0x18:pri[3]	offs=0x1f3c
block_row_dump:
tab 0, row 0, @0x1f7e
tl: 26 fb: --H-FL-- lb: 0x2  cc: 3
col  0: [ 2]  c1 0b
col  1: [10]  41 63 63 6f 75 6e 74 69 6e 67
col  2: [ 8]  4e 45 57 20 59 4f 52 4b
tab 0, row 1, @0x1f68
tl: 22 fb: --H-FL-- lb: 0x2  cc: 3
col  0: [ 2]  c1 15
col  1: [ 8]  52 65 73 65 61 72 63 68
col  2: [ 6]  44 41 4c 4c 41 53
tab 0, row 2, @0x1f54
tl: 20 fb: --H-FL-- lb: 0x2  cc: 3
col  0: [ 2]  c1 1f
col  1: [ 5]  53 61 6c 65 73
col  2: [ 7]  43 48 49 43 41 47 4f
tab 0, row 3, @0x1f3c
tl: 24 fb: --H-FL-- lb: 0x2  cc: 3
col  0: [ 2]  c1 29
col  1: [10]  4f 70 65 72 61 74 69 6f 6e 73
col  2: [ 6]  42 4f 53 54 4f 4e
end_of_block_dump
End dump data blocks tsn: 4 file#: 4 minblk 135 maxblk 135

1)lb: 0x2 表示改行数据被锁定,标志为2,它表示ITL事务槽的第二条事务信息;而第二条事务信息

的flag为空,表示没有提交,所以该行被锁定了(当然我们开需要查看事务表中的提交标志)。

2)Lck=4 表示锁定了4行数据。

锁的mode有如下几种

死锁-deadlock 
定义:当两个用户希望持有对方的资源时就会发生死锁. 
即两个用户互相等待对方释放资源时,oracle认定为产生了死锁,在这种情况下,将以牺牲一个用户作为代价,另一个用户继续执行,牺牲的用户的事务将回滚. 
例子: 
会话1,执行如下操作

SQL> conn scott/tiger
Connected.
SQL> update dept set dname=lower(dname);

4 rows updated.

会话2,执行如下操作

SQL> conn scott/tiger
Connected.
SQL> update emp set ename=lower(ename);

14 rows updated.

会话1,再执行对emp的更新

SQL> update emp set ename=lower(ename);

此时会话1被阻塞。

会话2,执行对dept表的更新

SQL>  update dept set dname=lower(dname);

此时会话2也被阻塞,但是会话1会报一个死锁的错误

SQL> update emp set ename=lower(ename);
update emp set ename=lower(ename)
       *
ERROR at line 1:
ORA-00060: deadlock detected while waiting for resource

会话1需要提交或者回滚,会话2才能正常执行。

Oracle的死锁问题实际上很少见,如果发生,基本上都是不正确的程序设计造成的,经过调整后,基本上都会避免死锁的发生。

时间: 2024-10-29 11:00:17

Oracle 学习之性能优化(十)锁的相关文章

Oracle 学习之 性能优化(十五) ASH、ADDM、AWR

ASH(Active Session History) ASH以V$SESSION为基础,每秒采样一次,记录活动会话等待的事件.不活动的会话不会采样,采样工作由新引入的后台进程MMNL来完成.ASH buffers 的最小值为1MB,最大值不超过30MB.内存中记录数据.期望值是记录一小时的内容. AWR(Automatic Workload Repository) 自动工作负载信息库 ASH 内存记录数据始终是有限的,为了保存历史数据,引入了自动负载信息库(AutomaticWorkload

Oracle 学习之 性能优化(十二) 分区表

一.分区概念 Oracle允许将表.索引.索引组织表细分成更小的片,每个片我们称之为分区.分区有其自己的名字和存储参数. 如下图: 每行数据只能属于一个分区,分区键决定数据行属于哪个分区.分区键由一个或多个列组成.Oracle自动的将数据的DML操作映射到相应的分区中. 何时使用分区表: Tables greater than 2 GB should always be considered as candidates for partitioning. Tables containing hi

Oracle 学习之性能优化(三)绑定变量

根据Oracle 学习之性能优化(二)游标中的描述,我们知道如下两条语句是不共享的. select * from emp where empno=7698; select * from emp where empno=7566; 这样就造成每次执行用户的查询都要进行硬解析,但是我们知道,其他这两个语句的执行计划应该是相同.那么有什么方法能避免不必要的硬解析吗?这里我们提供2种方法. 一.绑定变量 SQL> variable empno number; SQL> exec :empno := 7

Oracle 学习之性能优化(八)优化器

 我们知道,在sql语句解析的过程中,有一个过程叫优化.Oracle中有一个叫优化器的组件,专门来处理sql的优化.在考虑查询条件和对象引用的许多相关因素后,优化器能确定出执行SQL语句最有效的方式来.对于任何SQL语句,优化器优化的结果,可以极大地影响执行时间. Oracle优化器的优化方法有两种: CBO 基于成本的优化法则 RBO 基于规则的优化法则 初始化参数optimizer_mode控制着优化器优化的行为 SQL> show parameter optimizer_mode NAME

Oracle 学习之 性能优化(十三) 索引

一.索引概念 索引是一种供服务器在表中快速查找一个行的数据库结构.合理使用索引能够大大提高数据库的运行效率. 在数据库中建立索引主要有以下作用. (1)快速存取数据. (2)既可以改善数据库性能,又可以保证列值的唯一性. (3)实现表与表之间的参照完整性 (4)在使用order by.group by子句进行数据检索时,利用索引可以减少排序和分组的时间. 在关系数据库中,每一行都由一个行唯一标识RowID.RowID包括该行所在的文件.在文件中的块数和块中的行号.索引中包含一个索引条目,每一个索

Oracle 学习之性能优化(一)SQL语句处理

当向Oracle提交一个sql命令时,Oracle到底做了哪些事情?对这个问题有很好的理解,能帮助你更好的分析sql语句的优化. 执行一条sql语句从开始到结束,需要经历4个步骤: 分析--对提交的语句进行语法分析.语义分析和共享池检查. 优化--生成一个可在数据库中用来执行语句的最佳计划 行资源生成--为会话取得最佳计划并建立执行计划 语句执行--完成实际执行查询的行资源生成步骤的输出.对应DDL来说,这一步就是语句的结   束.对应SELECT来说,这一步是取数据的开始. 以上步骤,有的是可

Oracle 学习之性能优化(五)执行计划

读懂执行计划有什么用呢? 执行计划贯穿Oracle调优始终. 了解执行计划的真实执行过程,将有助于优化. 对亍Oracle的原理理解有一定帮助. 读懂执行计划,SQL调优的第一步. 什么是SQL Execution Plan执行计划? SQL是声明型语言,她只说我要去哪里,但很少告诉你到底如何去? SQL语句的执行最终会落实为Oracle执行步骤的组合 =>[SQL执行计划] 查看执行计划的方法 SQLPLUS AUTOTRACE Explain Plan For SQL SQL_TRACE 使

Oracle 学习之性能优化(九)使用hint

基于代价的优化器是很聪明的,在绝大多数情况下它会选择正确的优化器,减轻了DBA的负担.但有时它也聪明反被聪明误,选择了很差的执行计划,使某个语句的执行变得奇慢无比.此时就需要DBA进行人为的干预,告诉优化器使用我们指定的存取路径或连接类型生成执行计划,从 而使语句高效的运行.例如,如果我们认为对于一个特定的语句,执行全表扫描要比执行索引扫描更有效,则我们就可以指示优化器使用全表扫描.在Oracle 中,是通过为语句添加 Hints(提示)来实现干预优化器优化的目的. 不建议在代码中使用hint,

Oracle 学习之性能优化(六)访问路径

访问路径是指Oracle找到用户需要的数据的方法,这些方法很少,包括: 声名狼藉的全表扫描--人们不惜一切视图避免的(曲解的)访问路径. 各种类型的索引扫描--这是人们感觉良好的访问路径(多数情况下是被曲解的). 通过hash或者rowid的方式直接访问,通常对于单数据行来说,是最快的. 并没有一种访问路径是最好的,如果有,那么Oracle只需提供这一种访问路径就好了. 全表扫描 全扫描就是顺序的读取表中的所有数据块.采用多块读的方式,从头开始扫描表中的块,直到高水位线.全扫描是处理大数据量行之