使用10046跟踪Oracle前镜像数据读

来源:互联网 发布:淘宝拍摄平台 编辑:程序博客网 时间:2024/05/21 07:53

使用10046跟踪Oracle前镜像数据读

上一篇 /下一篇  2013-02-18 14:59:59 / 个人分类:Internal Research

查看( 100 ) / 评论( 2 ) / 评分( 15 /0 )

Undo前镜像”是Oracle早期推出的特性之一,也是在诸多数据库产品中异军突起的致胜法宝。当我们在一个会话中启动事务,对数据进行增加、修改和删除操作的时候,只要没有提交事务,其他会话只能看到数据的旧版本,也就是事务会话修改之前的版本。所以,在Oracle中,select操作不会阻塞任何操作,也不会被任何操作所阻塞。

 

 

1Undo与前镜像

 

这样的特性就是依赖Oracle推出的Undo前镜像机制。当我们开启事务,修改一个数据块的时候,Oracle首先会修改数据块块头的ITL事务槽)信息,将当前事务信息(xid事务标识)写入到ITL中的一行。之后标记下这个事务对应的Undo空间地址。之后,才能进行数据块的修改。

 

在修改数据块的过程中,OracleServer Process会将数据块的原有内容(对UpdateDelete操作而言),保存到Undo表空间上Undo段的位置上。

 

Undo段内容有很多的用途。当另外的会话需要访问数据块时,首先会去检查数据块的ITL事务槽信息,查看要访问的数据块是不是正在被修改。如果正在被修改,就根据ITL上面留下的事务槽信息访问Undo段。同时,如果只有一部分数据被修改,Oracle Server Process还要结合数据块中未被修改的内容进行结果集合拼装。

 

只有在事务正式完成,commit或者rollback之后,Undo段中的extent状态才不再是Active。非Active状态的Undo也有其价值,Oracle的“多版本一致读”、“Flashback”等特性,都是基于对非Active状态Undo的数据利用。

 

本篇,我们打算使用10046等待事件,监控一下Oracle是如何进行前镜像读取动作的。

 

2实验环境准备

 

我们选择11gR2版本进行试验。

 

 

SQL> select * from v$version;

 

BANNER

--------------------------------------------------------------------------------

Oracle Database11g Enterprise Edition Release 11.2.0.1.0 - Production

PL/SQL Release 11.2.0.1.0 - Production

CORE       11.2.0.1.0        Production

TNS for 32-bit Windows: Version 11.2.0.1.0 - Production

NLSRTL Version 11.2.0.1.0 – Production

 

 

创建实验数据表T

 

 

SQL> createtable t as select * from dba_objects;

Table created

 

SQL> select object_id from dba_objects where wner='SYS' and object_name='T';

 OBJECT_ID

----------

188217

 

SQL> select HEADER_FILE, HEADER_BLOCK, BYTES, BLOCKS, EXTENTS from dba_segments where segment_name='T' and wner='SYS';

HEADER_FILE HEADER_BLOCK     BYTES    BLOCKS   EXTENTS

----------- ------------ ---------- ---------- ----------

         1       89344  10485760      1280        25

 

 

对应分区信息。

 

 

SQL> select extent_id, file_id, block_id, blocks from dba_extents where segment_name='T' and wner='SYS';

 

 EXTENT_ID   FILE_ID  BLOCK_ID    BLOCKS

---------- ---------- ---------- ----------

        0         1     89344         8

        1         1     89352         8

        2         1     89384         8

(篇幅原因,省略部分内容……

       22         1     94592       128

       23         1     94720       128

       24         1     95616       128

25 rows selected

 

 

系统当前采用自动化Undo管理

 

 

SQL> show parameter undo;

NAME                                TYPE       VALUE

------------------------------------ ----------- ------------------------------

undo_management                     string     AUTO

undo_retention                      integer    900

undo_tablespace                     string     UNDOTBS1

 

 

3Trace文件获取

 

我们现在一个会话中,开启事务删除所有的数据。

 

 

SQL> select sid from v$mystat where rownum<2;

      SID

----------

      145

 

SQL> delete t;

84331 rows deleted

 

 

在另一个会话中,我们启动实验。注意,首选需要排除缓存脏块的影响,将脏块写入到数据文件。

 

 

--另一个会话

SQL> select sid from v$mystat where rownum<2;

      SID

----------

       21

 

SQL> alter system checkpoint;

System altered

 

SQL> alter system flush shared_pool;

System altered

 

SQL> alter system flush buffer_cache;

System altered

 

SQL> select value from v$diag_info where name='Default Trace File';

VALUE

------------------------------------------------------------------------------

d:\app\bspdev\diag\rdbms\ora11gw\ora11gw\trace\ora11gw_ora_2208.trc

 

 

开启跟踪操作过程。

 

 

SQL> alter session set events '10046 trace name context forever, level 12';

会话已更改。

 

SQL> select count(*) from t;

 COUNT(*)

----------

    84331

 

SQL> alter session set events '10046 trace name context off';

会话已更改。

 

 

我们可以在指定目录上找到对一个trace文件ora11gw_ora_2208.trc

 

4、结果分析

 

我们从trace原始文件中,发现了比普通FTSFull Table Scan)操作的不同。更多的操作细节和资源消耗。从直观上感觉,进行select操作消耗更多的时间。

 

Trace文件细节信息。

 

 

=====================

PARSING IN CURSOR #3 len=22 dep=0 uid=0 ct=3 lid=0 tim=156068168118 hv=2763161912 ad='30303208' sqlid='cyzznbykb509s'

select count(*) from t

END OF STMT

PARSE #3:c=234375,e=1924863,p=525,cr=4754,cu=0,mis=1,r=0,dep=0,og=1,plh=2966233522,tim=156068168115

EXEC #3:c=0,e=43,p=0,cr=0,cu=0,mis=0,r=0,dep=0,og=1,plh=2966233522,tim=156068168297

WAIT #3: nam='SQL*Net message to client' ela= 3 driver id=1413697536 #bytes=1 p3=0 obj#=188217 tim=156068168350

WAIT #3: nam='dbfile scattered read' ela= 14472 file#=1 block#=89345 blocks=3 obj#=188217 tim=156068182967

WAIT #3: nam='db file sequential read' ela= 14293 file#=3 block#=7522 blocks=1 obj#=0 tim=156068197389

WAIT #3: nam='db file sequential read' ela= 2580 file#=3 block#=7521 blocks=1 obj#=0 tim=156068200612

WAIT #3: nam='db file sequential read' ela= 2353 file#=3 block#=7520 blocks=1 obj#=0 tim=156068204231

WAIT #3: nam='db file sequential read' ela= 2355 file#=3 block#=7524 blocks=1 obj#=0 tim=156068207835

WAIT #3: nam='db file sequential read' ela= 2353 file#=3 block#=7523 blocks=1 obj#=0 tim=156068211050

WAIT #3: nam='db file sequential read' ela= 2352 file#=3 block#=7526 blocks=1 obj#=0 tim=156068215311

(省略部分内容……

FETCH #3:c=2265625,e=11162122,p=3131,cr=87951,cu=0,mis=0,r=1,dep=0,og=1,plh=2966233522,tim=156079330523

STAT #3 id=1 cnt=1 pid=0 pos=1 bj=0 p='SORT AGGREGATE (cr=87951 pr=3131 pw=0 time=0 us)'

STAT #3 id=2 cnt=84331 pid=1 pos=1 bj=188217 p='TABLE ACCESS FULL T (cr=87951 pr=3131 pw=0 time=21345344 us cost=329 size=0 card=86741)'

WAIT #3: nam='SQL*Net message from client' ela= 785 driver id=1413697536 #bytes=1 p3=0 obj#=0 tim=156079331506

FETCH #3:c=0,e=3,p=0,cr=0,cu=0,mis=0,r=0,dep=0,og=0,plh=2966233522,tim=156079331569

WAIT #3: nam='SQL*Net message to client' ela= 3 driver id=1413697536 #bytes=1 p3=0 obj#=0 tim=156079331615

 

*** 2013-02-18 08:20:42.187

WAIT #3: nam='SQL*Net message from client' ela= 43041122 driver id=1413697536 #bytes=1 p3=0 obj#=0 tim=156122372771

CLOSE #3:c=0,e=26,dep=0,type=0,tim=156122372940

=====================

 

 

系统操作消耗最大的部分,在于对数据块的读操作等待。从SQL的情况来看,Oracle只有全表扫描一条道路可以选择。而Oracle进行FTS操作的过程我们是清晰的。

 

在之前的文章中,我们讨论过FTS的操作过程。Oracle在进行FTS的时候,首先会从数据字典中定位数据头块位置,并且以单块读方式获取到头块。在头块分析中,Server Process获取到了数据段所有extents的分区信息,包括起始头块位置和块数量。之后根据这些信息进行一系列的多块读操作。

 

但是从我们看到的raw结果,Oracle在反复进行对file_id=1file_id=3文件块的读取。对1号文件的读取主要是多块读,但是大小远远小于我们的经验值。对3号文件完全是点读动作,一次只会读取一个数据块。

 

下面我们截取出一个片段进行分析。

 

 

WAIT #3: nam='db file scattered read' ela= 14472 file#=1 block#=89345 blocks=3 obj#=188217 tim=156068182967

WAIT #3: nam='db file sequential read' ela= 14293 file#=3 block#=7522 blocks=1 obj#=0 tim=156068197389

WAIT #3: nam='db file sequential read' ela= 2580 file#=3 block#=7521 blocks=1 obj#=0 tim=156068200612

WAIT #3: nam='db file sequential read' ela= 2353 file#=3 block#=7520 blocks=1 obj#=0 tim=156068204231

WAIT #3: nam='db file sequential read' ela= 2355 file#=3 block#=7524 blocks=1 obj#=0 tim=156068207835

WAIT #3: nam='db file sequential read' ela= 2353 file#=3 block#=7523 blocks=1 obj#=0 tim=156068211050

WAIT #3: nam='db file sequential read' ela= 2352 file#=3 block#=7526 blocks=1 obj#=0 tim=156068215311

WAIT #3: nam='db file sequential read' ela= 2467 file#=3 block#=7525 blocks=1 obj#=0 tim=156068218786

WAIT #3: nam='db file scattered read' ela= 6824 file#=1 block#=89349 blocks=3 obj#=188217 tim=156068229398

WAIT #3: nam='db file sequential read' ela= 2356 file#=3 block#=7531 blocks=1 obj#=0 tim=156068231844

WAIT #3: nam='db file sequential read' ela= 2457 file#=3 block#=7530 blocks=1 obj#=0 tim=156068234728

 

 

从标红部分可以看到,Oracle首先到1号文件读取了3个数据块,启示块号是89345。这个块是什么呢?

 

 

SQL> select owner, segment_name, EXTENT_ID, FILE_ID, BLOCK_ID, BLOCKS from dba_extents where file_id=1 and block_id<=89345 and block_id+blocks-1>89345;

 

OWNER     SEGMENT_NAME         EXTENT_ID   FILE_ID  BLOCK_ID    BLOCKS

---------- -------------------- ---------- ---------- ---------- ----------

SYS       T                            0         1     89344         8

 

 

显然,这三个块是数据表T第一个extent对应的分区数据块。Oracle在读取了之后,从ITL上知道了对应的Undo空间地址,就连续进行了7次对file_id=3的块操作,而且每次都是一个数据块。

 

我们随机找一下一个块的属性。

 

 

SQL> select owner, segment_name, extent_id, file_id, block_id, blocks, status from dba_undo_extents where file_id=3 and block_id<=7522 and block_id+blocks-1>7522;

 

OWNER     SEGMENT_NAME         EXTENT_ID   FILE_ID  BLOCK_ID    BLOCKS STATUS

---------- -------------------- ---------- ---------- ---------- ---------- ---------

SYS       _SYSSMU8_1557854099$        21         3      7424       128ACTIVE

 

 

很明显,Oracle在读了三个数据块之后,非连续(随机)的访问了Undo_SYSSMU8_1557854099$的第21分区中的一些数据块。目的很明显,就是获取前镜像,而且这些前镜像是进行单块读操作。

 

当完成所有的前镜像点块读之后,Oracle就可以合并出一致读的结果集。之后,在进行下3个块的读取动作。

 

5、结论

 

从上面的实验里面,我们可以得到几个想法。

 

首先,Oracle进行一致读的时候,每次进行多块读,获取的数据块数量是相对较少的。一般来说,多块读的上限规模和操作系统IO能力、Oracle内部多块读参数有关。但是在实例中,一次只会读出三块,猜想与一致读有关。

 

其次,在获取到数据块之后,Oracle会按照每个块中ITL信息,以单块的方式“点读”那些Undo块。并且进行合并结果集操作。

 

最后,从10046结构看,一致读是相当消耗资源的。在一致读状态下,检索性能要受到几个数量级别的影响。

 


原创粉丝点击