ORACLE在逻辑存储上分4个粒度:块、段、区、表空间。

2.1 块: 是粒度最小的存储单位,默认的块大小是8K,( 为什么Oracle要用数据块作为最小单位?因为,无论是Windows环境,还是Unix/Linux环境,他们的操作系统存储结构和方式、甚至字符排列的方式都是不同的。所以,Oracle利用数据块将这些差异加以屏蔽,全部数据操作采用对Oracle块的操作,相当于是对底层环境的一层封装。)ORACLE每一次 I/O 操作也是按块来操作的,也就是说当ORACLE从数据文件读数据时,是读取多少个块,而不是多少行。每一个Block里可以包含多个row。【延伸:mysql是页、区、段,pg最小单位也是块,本质一样。】


2.2 区:一系列相邻的块而组成,这也是ORACLE 空间分配的基本单位,举个例子来说,当我们创建一个表A时,首先ORACLE会分配一区的空间给这个表,随着不断的INSERT数据到A表,原来的这个区容不下插入的数据时, ORACLE 是以区为单位进行扩展的,也就是说再分配多少个区给A表,而不是多少个块。在进行存储数据信息的时候,Oracle将分配数据块进行存储,但是不能保证所有分配的数据块都是连续的结构。所以, 出现分区extent的概念,表示一系列连续的数据块集合。

  --查看区信息
  SET LIN 200 PAGES 999
  COL OWNER FOR A20
  COL SEGMENT_NAME FOR A20
  COL SEGMENT_TYPE FOR A10
  COL TABLESPACE_NAME FOR A10
  select  OWNER,SEGMENT_NAME,SEGMENT_TYPE,TABLESPACE_NAME,EXTENT_ID,FILE_ID,BLOCK_ID,BLOCKS  from dba_extents 
  where TABLESPACE_NAME='USERS' AND OWNER='SCOTT'  order by 7;
  



从视图中,我们可以清晰看出分区的几个特点:

首先分区是带有段特定性的。数据段segment是分区的上层组织单位,一个数据库对象对应一个segment,数据库对象是归属在不同的schema(owner)上的。所以,通过不同的数据段名称、不同的owner,乃至不同的tablespace表空间信息,就可以定位到数据区extent的信息描述。

另一部分信息是关于该区extent的分配信息,如所在文件编号,起始数据块block编号和数据块数量等内容。图中可以看到由于EXTENT_ID一致时,只需要定位开始的block就知道这些块是否连续,一般block_id间隔8。
这里再做一个测试,判断批量插入是否是连续的块:

  
-- 创建测试表a:
  
create table  scott.a (id number) tablespace users;
  
insert into scott.a  SELECT OBJECT_ID FROM DBA _OBJECTS;
  
commit;
  



从EXTENT_ID不一致分布,可以看到插入的时候并不是连续块插入的,而且采用随机I/O的插入到不同的区中,但是又有一定的规律。
那么为什么要写入不同的区中呢?

猜想:现在存储一般都使用磁盘阵列,提高存储性能的原理是把连续的数据分散到多个磁盘上存取,这样,系统有数据请求就可以被多个磁盘并行的执行,每个磁盘执行属于它自己的那部分数据请求。这种数据上的并行操作可以充分利用总线的 带宽,显著提高磁盘整体存取性能。
所以应该是为了能够充分利用每块磁盘的性能,所以才要写到不的分区中,也就是说分区概念中的连续的块集合,应该是一种块逻辑连续的概念,在物理上也不是连续的。

这里做一个10046的读取测试,看看读取时的信息:
  --10046测试
  ALTER SESSION  SET EVENTS '10046 TRACE NAME CONTEXT FOREVER,LEVEL 12';
  select count(*)  from scott.a;
  select value  from v$diag_info where name='Default Trace File';
  



可以看到先对1690这个块( 从dba_segments可以查到这个是个块头)做了一个单块读,获取其余块的信息,然后进行了一系列的多块读,可以发现一次 读取的最大块数为一个extent的大小,这里为8,所以分区在读取数据的意义应该是有一个限流的作用。
这里再扩展一个参数: db_file_multiblock_read_count,可以加大每次I/O获取的最大块数,但是还是会受extent大小的影响。

  
-- 创建测试表c:
  
create table scott.c (id number) tablespace users;
  
insert into scott.c SELECT  OBJECT_ID FROM DBA_OBJECTS;
  
insert into scott.c SELECT  OBJECT_ID FROM DBA_OBJECTS;
  
commit;
  
-- 设参数为20
  
alter system set db_file_multiblock_read_count=20;

--10046测试
  ALTER SESSION  SET EVENTS '10046 TRACE NAME CONTEXT FOREVER,LEVEL 12';
  select count(*)  from scott.c;
  
select value from v$diag_info  where name='Default Trace File';
  

-- 看到 C 表信息,看到 EXTENT_ID= 16 128 个块




-- 参数 db_file_multiblock_read_count 设为20


--10046 报告




从上图可以看到多块读的数量收到了参数 db_file_multiblock_read_count的限制。所以一些olap系统上可以提高这个参数,另外增大块大小来提高单次I/O的效率。

-- 第三个实验是把db_file_multiblock_read_count设为256,全表扫描C表,一次最大只能读取128这个块,因为这个参数不能超过一个extent的大小。




逻辑概念与物理存储关系图

2.2 段:是由一系列的区所组成,一般来说,当创建一个对象时(例如:表,索引),就会分配一个段给这个对象。所以从某种意义上来说,段就是某种特定的数据。如 CREATE TABLE A,这个段就是数据段,而 CREATE INDEX ON A(ID), ORACLE同样会分配一个段给这个索引,这是一个索引段。查询段的信息可以通过数据字典: SELECT * FROM DBA_SEGMENTS来获得。





2.4 表空间: Oracle的表空间属于Oracle中的存储结构,是一种用于存储数据库对象(如:数据文件)的逻辑空间,是Oracle中信息存储的最大逻辑单元,其下还包含有段、区、数据块等逻辑数据类型。表空间是在数据库中开辟的一个空间,用于存放数据库的对象,一个数据库可以由多个表空间组成。可以通过表空间来实现对Oracle的调优。


表空间实际上是由若干个数据文件来构成的,数据文件的位置和大小可以由我们自己来决定。数据被存放在表空间中的数据文件中。








管理表空间的方式:



字典管理表空间(Dictionary-ManagedTablespace简称DMT)

8i以后出现的一种新的表空间的管理模式,通过本地位图来管理表空间的空间使用。



本地管理表空间(LocallyManaged Tablespace简称LMT)

8i以前包括以后都还可以使用的一种表空间管理模式,通过数据字典管理表。



一、 本地管理表空间的由来:


在Oracle8I的版本中,Oracle推出了一种全新的表空间管理方式:本地化管理的表空间。所谓本地化管理,就是指Oracle不再利用数据字典表来记录Oracle表空间里面的区的使用状况,而是在每个表空间的数据文件的头部加入了一个位图区,在其中记录每个区的使用状况。每当一个区被使用,或者被释放以供重新使用时,Oracle都会更新数据文件头部的这个记录,反映这个变化。

  --查看表空间管理方式
  select tablespace_name,extent_management, allocation_type from  dba_tablespaces;

  

Oracle之所以推出了这种新的表空间管理方法,让我们来看一下这种表空间组织方法的优点:

       1. 本地化管理的表空间避免了递归的空间管理操作。而这种情况在数据字典管理的表空间是经常出现的,当表空间里的区的使用状况发生改变时,数据字典的表的信息发生改变,从而同时也使用了在系统表空间里的回滚段。

2.本地化管理的表空间避免了在数据字典相应表里面写入空闲空间、已使用空间的信息,从而减少了数据字典表的竞争,提高了空间管理的并发性。


3.从由数据字典来管理空闲块改为由数据文件的头部记录来管理空闲块,这样避免产生回滚信息,不再使用系统表空间里的回滚段。因为由数据字典来管理的话,它会把相关信息记在数据字典的表里,从而产生回滚信息。由于这种表空间的以上特性,所以它支持在一个表空间里边进行更多的并发操作,并减少了对数据字典的依赖。


二、本地管理表空间管理机制


8i之前所有的表空间都是采用字典管理模式,ORACLE需要有一个机制来管理表空间中各数据文件的这些分配的或未分配的空间,为了跟踪这些可以使用的空间(包括未分配使用的和可以重复使用的),对于每一个空间,我们必须知道:


      1、这个可用空间位于什么数据文件;
      2、这个空间的尺寸是多大;
      3、如果它在用了,是哪一个段占用的这个空间;


为了确保能保存以上的信息,ORACLE用了两个数据字典表:UET$(已使用的区间)或FET$(空闲空间):



查询该表可以看到,每个使用空间或空闲空间(不一定是一个extent,可以是多个extent)都在该表中对应了一行。它的工作方式是当一个段被删除的时候,ORACLE就移动UET$中相应的行到FET$,这个过程的发生是连续的,而且可能发生等待。当并发性很高的时候,数据字典的争用就来了。另外有一个问题就是,当表的空间很不连续或表空间有大量的碎片引起这两个表的增大,那么也就会引起数据库性能上的下降。


本地管理表空间正是为了解决这一问题来的,在表空间的空间管理上,ORACLE将存储信息保存在表空间的头部的位图中,而不是保存在数据字典中。通过这样的方式,在分配回收空间的时候,表空间就可以独立的完成操作也不用与其它对象关系。
Logo

更多推荐