Chinaunix首页 | 论坛 | 博客
  • 博客访问: 92255219
  • 博文数量: 19283
  • 博客积分: 9968
  • 博客等级: 上将
  • 技术积分: 196062
  • 用 户 组: 普通用户
  • 注册时间: 2007-02-07 14:28
文章分类

全部博文(19283)

文章存档

2011年(1)

2009年(125)

2008年(19094)

2007年(63)

分类: Oracle

2008-05-01 18:00:53

Wwj/scttsc
Valenwon/cnoug
2008 Apri 7


昨天为了提高fact table装载数据效率(同事写的etl代码,效率达不到要求),对Oracle的插入机制做了一些学习。虽然最后提高效率的关键还是在于Java code上,但是对Oracle并发写入原理有了一定的了解。

Oracle插入数据的时候,首要做的工作就是寻找可使用的数据块(HW下面未满数据块,HW上面未格式化的数据块),如果没有则会增加extent
Oracle以前版本(9i。。)使用freelist来管理可空闲块,为了保证并发时候数据的完整性,一个进程在修改freelist前,必须锁定它,这样必然就会产生竞争。优化办法是采用多个freelist,但是又得考虑在空间和效率上获得折衷的数量。由于已经过时,不在研究。
Oracle10g中,ASSM已经称为segment管理的默认配置,在ASSM中是采用位图来管理空闲块。一般是两级位图块,如果数据量很大,可能会出现三级(itpub版主做过试验)。关于位图块的概念,网上很多,不做讲解。
继续采用《Oracle如何计算consistent gets》一文中的测试表TEST1,不过删除掉一些记录,构造一些没有满的块。
找出段头
SQL> SELECT s.header_file,s.header_block FROM dba_segments s
WHERE s.segment_name = 'TEST1';
HEADER_FILE HEADER_BLOCK
----------- ------------
5     11
dump出块内容
SQL> alter system dump datafile 5 block 11;
省略了其它内容,直接看感兴趣的部分
。。。
Second Level Bitmap block DBAs ――二级位图块的地址
--------------------------------------------------------
DBA 1:   0x0140000a   -唯一一个二级位图块
。。。
0x0140000a 只需要后半部分,a 转换为10机制就是10,那么继续dump block10
SQL> alter system dump datafile 5 block 10;
一个二级位图块的内容节略如下:
Dump of Second Level Bitmap Block
number: 5   nfree: 2   ffree: 0   pdba:   0x0140000b
Inc #: 1 Objd: 51344
opcode:0
xid:
L1 Ranges :
--------------------------------------------------------
0x01400009 Free: 5 Inst: 1 转换为10进制为 9
0x01400ce9 Free: 1 Inst: 1 转换为10进制为 3305
0x01400cf9 Free: 1 Inst: 1
0x014000c1 Free: 1 Inst: 1
0x014000d9 Free: 5 Inst: 1 转换为10进制为 217



--------------------------------------------------------
End dump data blocks tsn: 6 file#: 5 minblk 10 maxblk 10


继续dump 9 3305

SQL> alter system dump datafile 5 block 9;
SQL> alter system dump datafile 5 block 3305;
Block 9的节选内容如下:
--------------------------------------------------------
DBA Ranges :
--------------------------------------------------------
0x01400009 Length: 8   Offset: 0   开始地址
0x01400ce1 Length: 8   Offset: 8   结束地址

0:Metadata   1:Metadata   2:Metadata   3:75-100% free

4:75-100% free   5:75-100% free   6:75-100% free   7:75-100% free
8:75-100% free   9:75-100% free   10:75-100% free   11:0-25% free
12:FULL   13:FULL   14:FULL   15:FULL
--------------------------------------------------------
这里可以清晰的看出,第0 1 2是元数据块,实际就是我们dump 9 10 11块,411块都有空闲空间,那是因为我在试验开始删除部分数据。
Block 3305的节选内容如下:
--------------------------------------------------------
DBA Ranges :
--------------------------------------------------------
0x01400ce9 Length: 8   Offset: 0  
0x01400cf1 Length: 8   Offset: 8  

0:Metadata   1:FULL   2:FULL   3:FULL

4:FULL   5:FULL   6:FULL   7:FULL
8:FULL   9:FULL   10:FULL   11:FULL
12:FULL   13:FULL   14:FULL   15:FULL
这个位图可以看出,除了它本身是metadata以外,其它它管理的块都是转满了数据的。
通过这些信息,对Oracle如果管理块就有一定的了解了。
那么Oracle是如何在并发插入的时候分配块呢?
为了观察数据的情况,我建了一个新出测试表:
create table TEST4
(
C1 CHAR(
2000)
)

PLSQL dev里面测试,插入7行数据1234567
SQL> select dbms_rowid.rowid_block_number(t.rowid) from test4 t order by c1;


DBMS_ROWID.ROWID_BLOCK_NUMBER(T.ROWID)

--------------------------------------
              236
              236
              236
              237
              237
              237
              238
这个时候Oracle是采用挨着写数据块,写满一个换下一个的办法。删除数据。。。
模拟并发写入,我打开了7SQL windows。我笔记本的测试库,是dedicate模式,oracle为这个7windows分配了7process7session)。
我分别插入1234567,注意都不要提交。
插入完毕,分别提交。
观察数据分布:
SQL> select dbms_rowid.rowid_block_number(t.rowid) from test4 t order by c1;


DBMS_ROWID.ROWID_BLOCK_NUMBER(T.ROWID)

--------------------------------------
              236
              237
              238
              239
              239
              240
              236
在这个extents中,8个块,有5个可用写入数据块。236240
SQL> SELECT s.block_id,s.blocks FROM dba_extents s WHERE s.segment_name = 'TEST4';


BLOCK_ID   BLOCKS

---------- ----------
233               8
为了获得更好的并发性能,Oracle显而易见的采用了尽量为每个process分配不同的块。
为什么说尽量呢?如果所有的空闲块都分配完,那么就还是会吧已经分配完的块,再次分配给新来的process,这也是结果里面,239236块多次使用的原因。
Oracle为什么不为每个process分配独立的块,这样虽然达成了最大并发,却可能严重浪费空间,所以这又是一个性能和空间的折衷。
Oracle是怎么选择使用那个块呢?应该是先锁定一个位图块,再分配,由于存在多个二级位图块(本例只有一个),所以提高了并发,再锁定,并在位图块里面分配不同的块。但这个算法,我不清楚。
Oracle“尽量”为每个process分配独立的块,已经是很大的进步了,那么如果多个process共用一个块,情况又是怎么样的呢?
这个时候,我们的研究对象,有变成了Data buffer
Oracle某个process 找到一个可用块的时候,做的第一件事情,并不是要去写它,而且把它读取到Data buffer中。Oracle是通过各种“锁”,来保证对资源的并发访问。(说白了,再快的并行,其实在某一局部也是串行,只不过这个串行相当的快罢了,在多线程编程中经常遇到,实际应用中几乎没有全盘的并发,只是把效率低下的部分并发来配合效率高的部分。。。)
Oracle通过一个Hash链来维护databuffer header,每一个Hash bucket里面存储着Ndatabuffer headerHash key 是相关的data block addressblock class
Oracle用户进程找到某一个块,准备写入的时候,会在相应的databuffer header加锁,也就是我们常说的latch,避免同时被其它进程同时访问块,加上锁以后,用户进程会立刻在块里面更新SCN,打上事务标记,并且锁定要使用的行,释放latch。这个时候,下一个用户进程才得以重新重复以上动作。虽然上面的步骤貌似很多,但是实际是在相当的快的。
通过使用latch,使得用户进程可用并发的使用块,各自处理自己锁定的行。 latch则是串行。
算了,Buffer cache重新再另一文章总结。



小结:总得来说,10g里面,Oracle的并发插入已经比较高效,但是也不排除在高度并发并且采用Dedicate的环境中,会出现性能问题(latch竞争)。但在Mts下,一般连接池问题不大。

原文:http://valen.blog.ccidnet.com/blog-htm-itemid-279264-do-showone-type-blog-uid-51502.html
阅读(609) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~