http://v.youku.com/v_show/id_XMzkyMTk3ODM2.html
首先简单说明一下Oracle数据库的结构.
1. 数据库的作用:
1.存储数据
2.方便地检索和处理数据.
2.Oracle的简单结构
1.存储数据( Oracle 文件)
2.方便地检索和处理数据. ( Oracle 实例)
可见对于Oracle数据库来讲, 数据都是存放在Oracle文件中的.
而前面章节也提到过, Oracle文件分3大类, 控制文件/ 数据文件 / 重做日志文件 --> 归档日志文件
实际上数据库所有数据都存放在数据文件中的, 重做日志文件只不过是记录了 数据文件的数据变化,而不是数据文件的一份copy.
3. 数据文件的3层结构(block, extend, segment)
详细可以参考我翻译的官方文档啦:
http://nvd11.blog.163.com/blog/static/200018312201282354948602/
下面是简单介绍:
Oracle 的数据文件在物理上可以分3层结构,就是块(block)/区(extend)/段(segment) 啦.
其中最基本的单位是block
而extend是由一段 物理上连续的block组成的单位.
segment是由若干个extend(无需物理连续)的extend组成的.
大概结构如下图:
如上图,可以看出一个表空间内有两个数据文件, 里面3个extends组成1个数据段
仔细观察可以分析出:
* 1个表空间可以有多个数据文件. 但1个数据文件只能存在于1个表空间内(不能跨表空间)
* 在1个表空间内每个block的 大小是相同的
* 每个extend 都是由连续的blocks组成, 所以1个extend只能在1个数据文件中(不同数据文件中的block肯定不连续的啦).
* 1个segment 由若干个extends组成, 这些extends不必物理连续, 所以 segment可以跨数据文件保存.
* 1个segment只能存放在1个表空间内 , 不能跨表空间
一般来讲, 一个segment就用来存放1张表或索引的数据, 如果这个segment是存放表的就叫数据段, 如果是存放索引的就叫索引段.
Oracle 1个segment只能存放在1个表空间内 ,是不是代表1张表不能跨表空间存放数据呢.
大部分表都是存放在1个表空间内的,但是有例外, 这就是分区表 .
有些表由于数据量实在过大, 可以根据一些规则(如地区), 分开存放在若干个表空间, 每个表空间中有1个(只能有1个)segment内存放这个分区表的数据. 这样的话 检索1个地区的数据就只访问1个表空间内的数据文件就ok了.
也就是说 分区表可以又多个segments组成, 但是每1个segment都存放在不同的表空间中.
如下图啦:
4,段区块的分配
当user建立一张表, Oracle就会为这种表分配1个数据段, 同时分配1个extend, 这张表的数据就存放在这个extend的blocks中, 当其blocks用完时, Oracle会重新1个extend到这个数据段, 而不会单独第分配个1个block.
5.Block是Oracle最少的磁盘IO单位
一般来讲, Oracle block 大小是8k, 也可设成12k, 16k等....
可以用show parameter block; 来查看当前数据库的Blocksize.
也就是说Oracle dbf被分成了很多个大小为8k的小块
而Block是Oracle最小的磁盘IO单位.
点讲咧~
其实我们知道oracle是将数据存放在block中的, 一般情况下, 1个block能存储对应表的多个数据行. 而不会将1个数据行分开存放到多个blocks中, 除非这个数据行是在太大(行链接), 或者其他原因(行迁移)
假如这个时用户要访问这张表1条数据行的数据, 而且提交了sql语句, Oracle经过计算, 算出了这个数据行存放在哪个block中, 虽然这个block存放了多个数据行. 但是Oracle并不会只访问这1条数据行的数据, 而是将整1个block从dbf文件中读取到Data buffer cache中.
如上图, 即使这个block有多个数据行的数据, 但是为了读取其中1行, oracle都会将整个block的数据读入db buffer cache.
然后server process 会在database buffer cache的这个block的数据里提取出用户想要的数据行, 并将其发送给用户.
实际上, 当用户修改了这个数据行, Oralce也会把缓存中整个block的数据一次写入回DBF文件
所以讲block是oracle的最小磁盘IO单位.
6. 同样地, 对应dbf文件. sga里的 database buffer cache也被划分成许多个小块.
可以理解,在sga中, Database buffer cache就是用来专门用来缓存dbf文件的数据的, 而dbf文件是1个1个block(最小IO单位)地被读取入database buffer cache里的, 所以 database buffer cache也会被画成对应的许多个小块, 只不过这些块在database buffer cache被称为 buffer, buffer的大小与block是一致的.
7. dababase buffer cache 的意义.
其实意义有两个
1. 减少物理IO
2. 构造CR块
7. 1 减少IO
假如用户要检索一张表的第11条数据行, 那么Oracle经过计算后, 第11条数据行在某个block中, 那么Oracle会执行如下动作.
1. Oracle计算这条数据行在对应表数据段的哪1个block中.
2. 在内存(database buffer cache)里找, 看看有没有与那个block对应的buffer.
3. database buffer cache中没有, 则Orocle会向操作系统发送1个物理IO请求.( 没有命中)
4. IO请求被发送到磁盘中, Oracle会读取dbf文件中读取这个block, 放入db buffer cache中, 形成了与这个block对应的buffer( 物理读)
5. Oracle在database buffer cache中读取这个buffer的对应行,并返回给用户.( 逻辑读)
可以见到这个过程中发生了1次物理IO
这时,用户又想查看第12行, Oracle经过计算, 也算出了具体哪个block..
2. 在内存(database buffer cache)里找, 看看有没有与那个block对应的buffer.
3. 这次找到了(11行和12行再同1个block中)( 命中了), 读取这个buffer的对应行,并返回给用户.( 逻辑读)
可见第二次读取时, 避免了物理读.
7. 2 构造CR(consistent read)块
这个跟事务有关了.
假如一张表T1 , 里面有两行数据, 这两行数据都存放在1个block中.
这时 有1个session 1 来访问这张表的所有数据(select * from T1), 那么Oracle就会将这个block数据提取到database buffer cache中,形成1个buffer, 对应 session1 的 Server Process A就可以从这个buffer 中访问表T1的数据了.
同时, 又有另1个session 2执行同样的语句(select * from T2), 那么server process B就可直接在database buffer cache 找到这个buffer, 这样与session 1一样, server processB 也可以访问这个buffer 找到T1的数据.
如下图:
好了, 如果这时, session 1把 T1表其中的一行删除了, 那么对应buffer的row1数据就清除掉, 但是session 1并没有提交, 所以这个buffer就成了脏数据( 严格来讲, 即使session 1提交了, 但是DBWR未写回数据文件, 这个buffer还是脏的,只有与数据文件数据1至才是干净的).
如图
那么session2 是否会再一次从数据文件中把对应block数据放入database buffer cache中呢(物理读)?
1.不是这样的, 因为session1 修改了数据的同时(删除row1), 虽然并没有commit,但是会产生undo log(撤销日志). 注意不是redo log(重做日志), 当commit之后就会产生redo log.
2. 这时session去检索这个buffer时, 发现数据已经被更改. 就会在database buffer cache申请多1个block size的空间, 并将被修改后buffer的数据copy一份放入这个新的buffer中.
3. 但是这个新的buffer数据还是跟旧的一样啊, 也就是脏的啊, 所以session2 会从undo log中找回对应删除row 1的数据, 将这个新buff回滚到初始状态, 这样session2 就能读取这个新buffer了, 而这个新的buffer 就是CR 块了( consistent read block). 而且避免了物理读.
如下图:
其实我们在这个流程中发现 undo log有两个作用, 第一就是帮助 session2 构造CR 块, 提高数据库并发性.
第二个作用也明显, 当session1 后悔了, 不想提交这个改动, rollback的时候就会通过undo log把数据修改撤销回到那个脏的buffer里啦.