(一)
一直以来对“块”的概念总是含混不清,从字面意义理解,只知道这是ORACLE存放数据的最小单位,然而它的内部世界如何呢,本人打算从今天开始连载几篇文档,对它进行深度分析。
通过很多文档、资料,了解到了数据库基本结构鱼刺图:
基本上每个对象对应一个段( Segment),只有分区对应多个段,这里的对象包括table,index,partition等等,段可以跨越多个数据文件。
每个段又有多个区(extent)来组成,这些区不能跨越多个数据文件,同时在系统使用过程中自动扩展。
最后是块(block),所有的数据都是存放在块中。为了适应操作系统,每个块在创建数据库的时候默认了一个大小,这个大小一般是8K,同时在9I及其以 后的版本中增加了不同大小的块参数,这将在以后的实验中体现。先说说这个8K大小的块,一般来说,为了使得oracle运行读写数据文件的时候有一个合理 的吞吐量,这里的块大小,都跟操作系统块大小设为整数倍,例如ntfs格式化的磁盘文件,每个物理块大小为4,这里oracle的块大小为8,即是代表每 读取一个oracle块,其实物理上也就是读取了两个操作系统块。 这里主要指的是数据文件存放在块设备上,在实际的生产环境中,大部分情况都是将数据库安装在裸设备(RAW)也叫做原始分区之上。关于RAW将在以后进行 讲解。
通过上面这段文字,我们可以了解到ORACLE基本的存储结构,下一篇将针对块的大小与存放数据大小来做实验。
(二)
上一节了解到了ORACLE的存储结构,这节讲一讲块的大小与数据存放之间的关系。
大家都知道了在ORACLE环境中,所有的对象都是存放在块中,这个块大小与存放的记录之间到底存在怎样的关系呢?
做一个实验看看:
创建一个表空间test
create tablespace test datafile '/oracle/oradata/test.dbf' size 100m;
创建一个用户
create user test identified by test default tablespace test;
创建一个表
create table test.t1 (a1 number,a2 varchar2(100));
检查段,可以发现在这个视图中出现了名称为T的段,段类型为TABLE,这个段里面分配了1个区,其中包含8个块,大小为64K字节。
select segment_name,blocks,extents,bytes,segment_type,tablespace_name fromdba_segments where owner='TEST';
SEGMENT_NAME BLOCKS EXTENTS BYTES SEGMENT_TYPE TABLESPACE_NAME
---------- ---------- ---------- ---------- ------------------ ----------
T 8 1 65536TABLE TEST
检查区,可以发现在这个视图中出现了一个区,区号为0,包含8个块,大小为64K字节。
select segment_name,segment_type,extent_id,blocks,bytes from dba_extents whereowner='TEST';
SEGMENT_NAME SEGMENT_TYPE EXTENT_ID BLOCKS BYTES
---------- ------------------ ---------- ---------- ----------
T TABLE 0 8 65536
检查块,可以发现这里没有载入到内存的块,由此断定,在数据未写入的时候,内存中并没有存放数据的块。
select file#,block#,class#,status,xnc,objd from v$bh where ts#=12;
未选定行
插入10行数据,进行测试。
SQL> declare
2 i number
3 ;
4 begin
5 for i in 1..10 loop
6 execute immediate 'insert into test.t values (:x,:y)'using i,i;
7 end loop;
8 end;
9 /
PL/SQL 过程已成功完成。
再次查看v$bh视图,检查内存中是否使用到了块。
select file#,block#,class#,status,xnc,objd from v$bh where ts#=12;
FILE# BLOCK# CLASS# STATU XNC OBJD
---------- ---------- ---------- ----- ---------- ----------
1 28089 4 xcur 0 11038
1 28090 1 xcur 0 11038
哈哈,果然出现了数据,说明在数据插入的表的时候在内存中已经载入了分配的块,同时在这些块中写入了数据,这里占用了两个块,块号分别为28089,28090,其中我们可以根据CLASS#来判断出他们属于不同类型。
(三)
这一节紧接着上一节来说。
上一节通过实验,我们了解到,块的创建和读取流程,不过只是针对一个会话的,现在我们来看看在一个会话中插入数据之后,同时在另外一个会话查询数据,这样的情况会对块有什么影响。
打开一个新的会话, 然后执行如下命令:
查询表,由于插入数据的事务没有提交,这里在另外的会话中就看不到任何数据,深深体现了ORACLE的多版本一致性
select * from test_gao.t;
未选定行
查询视图v$bh,看是否有了变化
select file#,block#,class#,status,xnc,objd from v$bh where ts#=12;
FILE# BLOCK# CLASS# STATU XNC OBJD
---------- ---------- ---------- ----- ---------- ----------
1 28089 4 xcur 0 11038
1 28090 1 cr 0 11038
1 28090 1 cr 0 11038
1 28090 1 xcur 0 11038
果然和上一节查询出来的结果不同,多了红色字体标识出来的两行,大家可以看到这两行的STATUS字段值为cr,什么是cr呢?它是Consistency Read(一致性读取)的缩写。从这里可以看出28090这个块被两个会话进行了操作。
在第一个会话中回滚事务会发生什么呢?看下面的操作:
会话1:执行rollback
SQL> rollback;
回退已完成。
再次查询v$bh视图,看看什么情况
select file#,block#,class#,status,xnc,objd from v$bh whereobjd=11038;
FILE# BLOCK# CLASS# STATU XNC OBJD
---------- ---------- ---------- ----- ---------- ----------
1 28089 4 xcur 0 11038
1 28090 1 cr 0 11038
1 28090 1 cr 0 11038
1 28090 1 xcur 0 11038
结果还是一样,说明在事务回滚之后,块还是处于一致读取的状态。
(四)
我们继续上一节的话题。
关闭数据库实例
SQL> shutdown immediate
数据库已经关闭。
已经卸载数据库。
重新打开数据库
SQL>startup
ORACLE 例程已经启动。
Total System Global Area 253214492 bytes
Fixed Size 454428 bytes
Variable Size 117440512bytes
Database Buffers 134217728 bytes
Redo Buffers 1101824 bytes
数据库装载完毕。
数据库已经打开。
检查v$bh视图
select file#,block#,class#,status,xnc,objd from v$bh where objd=11038;
未选定行
说明在没有进行块中数据的相关操作的时候,并没有从物理文件中提取块到内存。
执行查询或者插入、更新的SQL语句
SQL> insert into test.t values (200,200);
已创建 1 行。
再次检查v$bh视图
SQL> select file#,block#,class#,status,xnc,objd from v$bh where objd=11038;
FILE# BLOCK# CLASS# STATU XNC OBJD
---------- ---------- ---------- ----- ---------- ----------
1 28089 4 xcur 0 11038
1 28090 1 xcur 0 11038
总结:在没有进行物理I/O的时候,v$bh视图中不会出现相关的块信息,同时证明此视图中存放的乃是数据文件块放到内存中的“块”信息。