DBA之路--体系结构_数据库—逻辑存储结构

逻辑存储结构数据库

代码所控制的文件,类似linux的lvm由物理卷生成的逻辑卷,不是真正的文件

oracle以逻辑形式使用存储空间,由以下块、区、段和表空间单元构成。

  • 表空间,TableSpace是存储结构中的最高层结构,作为段结构的逻辑存储容器。建立一个表空间的时候,是需要指定存储的文件。具体划分为永久表空间和临时表空间

    一个表空间可以指定多个数据文件,多个文件可以在不同的物理存储上.

  • 段segment,与数据库对象对应,一个对象一个数据段。

    Oracle 体系结构(20)—— Oracle 的段(segment)管理_oracle segment_睿思达DBA_WGX的博客-CSDN博客

    是作为表空间内某一个逻辑存储结构表的所有数据扩展分区extent的集合,一个用户段可以包含很多类型:

    表及表分区、lob及lob分区、索引分区及索引,回滚,聚簇。

    #针对段的不同区情况,每个段都有段头 header block包含记录一个段的所有区的目录
    
    #在数据库中段对表有两种情况:
     #1、只有几百条几千条数据的普通小表(专业说法叫堆表),一张表就是一个段,该表的初始扩展区和增量扩展区直接构成一个段
     #2、如果一张表体量巨大几亿条千万条这种,oracle会基于某种规律将整体分成多个分区表,每个分区在整体逻辑上属于一张表,但每表个分区partition又单独成表各自存储一部分数据,分区结构保持一致。这些分区表的各自构成一个段segment,整个segment集合才是这张表实际占用的段。
    
    https://blog.csdn.net/wbj19890107/article/details/44101719
    #段的种类
     #1、临时段(未进行设置时,默认为临时表空间、临时表使用)
       #Oracle 数据库通常在SQL 语句执行的中间阶段需要临时工作区。可能需要临时段的典型操作包括排序、哈希、和合并位图。当创建索引时,Oracle 数据库将索引段置于临时段,然后当索引创建完成时将其转换成永久段。如果一个操作可以在内存中执行,则Oracle 数据库不会创建一个临时段。不过,如果不能使用内存,则数据库自动在磁盘上为其分配临时段。
       
     #2、撤销段-主要是回滚
      #默认就是undo表空间中。
      #当事务启动时,数据库将此事务绑定到(分配给)一个撤消段,并因此也绑定到当前撤消表空间中的一个事务表。多个活动事务可以同时写入同一个撤消段或不同的撤消段。
      #从概念上讲,一个撤消段中的扩展区形成一个环。事务先写到一个撤消扩展区,然后写到环中的下一个扩展区,循环往复。
      
     #3、用户段
      #实际存储业务数据的段,表,表分区或表簇,LOB或LOB分区,索引或索引分区
    
    SELECT SEGMENT_CREATED FROM DBA_TABLES WHERE TABLE_NAME='CLUSTERTEST'
    #查询表对应的段创建成功结果
    
    #验证段创建结果
    create table test(id number,name varchar2(20));
    insert into test(id,name) values(1,'test');commit;
    select segment_name,segment_type,tablespace_name,bytes,blocks,extents from user_segments;
    
  • 区extent,由一组连续的数据块构成的数据库逻辑存储分配单位,用于保存特定数据类型。

    用于表示一段连续的数据块集合,默认数据库表由多个区(初始扩展分区和增量扩展区)构成是一个一对多关系

    当用户创建一张表用于存储数据时,oracle会对应数据段分配一个包含多个块的初始区,当一个段的数据块已满且需要插入新数据时,会额外分配一个增量区

    #由于区的相关参数基本上都被包含于段的存储参数中,段和区的参数会一起讲解
    show parameter deferred #段创建参数生效与否,为true创建表时创建区,false则不创建区不分配空间
    desc dba_extents #此表主要面向extent信息存储
    
    #创建表指定分区大小
    create table test2 storage(initial 10m) tablespace test 
         as select * from scott.emp;#指定初始大小10
    #手动扩展extent
    
    #实验验证extent区
      #表空间内创建一张表
      create table tbaletest.extenttest(id varchar(200),name varchar(400));
      #查找对应生成的区,没插入数据所以没有结果
      select file_id,block_id,blocks,extent_id from dba_extents where segment_name='TESTEXTENT'
      #再插入数据,然后在检查返现段增多
        #我这边是拿wps弄了两列总计2000行等比数列的保存为csv格式。然后用 plsql导入表中的,省事儿
        select file_id,block_id,blocks,extent_id from dba_extents where segment_name='TESTEXTENT';#会发现分配了一个8个块block大小的初始扩展分区
    
    #自动创建扩展分区验证
      #上面的数据多导入几遍,然后插入数据
      
      
      
    #删除数据后回收扩展区---高水位问题解决方式
     #高水位问题,可以简单理解为oracle没有回收某张表内已经被删除的数据的所占空间(块),导致实际使用空间小于占用空间,做ETL或者迁移时会经常碰到,不是本题重点。本次利用上面的表做演示。
     #1、随机删除几条数据
     delete from extenttest where rownum <3000; commit;
     delete from extenttest where rownum <2000; commit;
     #2、查看区空间使用情况
     select file_id,block_id,blocks,extent_id from dba_extents where segment_name='TESTEXTENT'; #应该是与未执行删除前的查询结果一致,该表的空间没有被oracle进行回收
     #3、回收多余区
     alter table extenttest enable row movement
     #进行行移动(块的行迁移触发)(将源数据的空间指向新空间)
     alter table extenttest shrink space;#收缩空间(压缩段,处理数据碎片降低高水位,减少性能损耗)这里干脆将原数据块链接干掉,新数据块直接关联表
     select file_id,block_id,blocks,extent_id from dba_extents where segment_name='TESTEXTENT'; #查询结果会变少
    
  • 块block,oracle逻辑结构的最基本的最小存储和IO单位。

    快内部有数据块头、表目录、行目录空闲空间和行数据构成。只有表中有数据,表空间才会产生对应块,否则就只有元数据。

    #目前仅有2、4、8、16、32kb五种大小,创建后就不可更改,除非重新创建数据库。一般情况下每次向表内插入一行数据,都会产生至少一个块,下面有一个c版本的实验做验证。
    select id, dbms_rowid.rowid_relative_fno(rowid) file,dbms_rowid.rowid_block_number(rowid) block from test;
    show parmeter db_block_size #指定逻辑块基本大小
    
    #数据块结构
    header+table directory+row directory+free space+row data
    数据块地址+表目录+行目录+空余空间+使用空间
    
    #块中的伪列row_id-区别块唯一标识(块是区的基本结构,唯一只针对同一区(表)内)
      #oracle中使用row_id标识为一行,对块内部时row_id实际为一个结构,也是元数据但不实际存在再数据库中,是由数据文件和块进行推导而来。在默认是表内(区结构的)唯一的row_id.
      #由上述,所以row_id不能修改也不能删除,可以进行快速删除数据(删的是数据,当前的row——id会被推导指向另外的块)
      
      
    #块中的行链接与行迁移--单次插入行数据过多,单一一个块不够用
     #针对这种情况,数据库会将该行的数据存储在为行片段保留的一个或者多个链接的数据块中。每个数据块的header都会存储被链接的下一个块的地址。这种行为被细分为行链接与行迁移
     #1、行链接--insert常见
      #行允许容纳块中每个块最大255个行,当一个1000个列的表中插入数据,数据库会同步创建最少4个行片段,每个行片段链接多个块的方式,请参考c的链表,大行的一整个链接作为一个链表存在。每个块存储该行数据的一部分,全部块构成一整条行数据,这种称为行链接,前提是这几个块没有其他数据
      出现类型:long\long row\lob
      预防措施:show parmeter db_block_size #可以通过修改参数将块的基本大小进行扩充防止其发生
      
     #2、行迁移--update常见
      #当一个块的空余空间不足以容纳当前插入的行数据时,oracle会将该数据从当前块移动到一个块中,仅在被迁移的原块中保留一个指针指向迁移的新块,同样存放在header中
      预防措施:将block的pctfree调高,扩展block大小
      
    #无论是行迁移还是行链接,执行时必定会检索数据。当发生该情况时会额外占用IO性能
     #下面附带一个验证实验
    
    #验证块的实验
    #切换到pdb插拔数据库的表空间下,如果是g版本或者已经c版本有做过修改tnsname.ora请忽略该步骤1、2,直接跳到3
     #1、sqlplus空闲进程登入CDB$ROOT,创建测试用pdb,同时检查情况
      CREATE PLUGGABLE DATABASE pdbCreateTest2 ADMIN USER pdbCreateTest2 IDENTIFIED BY pdb2
    STORAGE (MAXSIZE 1G MAX_SHARED_TEMP_SIZE 50M)
    DEFAULT TABLESPACE pdbCreateTest2
      alter pluggable database pdbCreateTest open;#数据库开启
      show pdbs #pdb对应,open mode变为read write即可
    #2、将当前容器切换为新创建的pdb容器,在tnsname.ora文件中添加该pdb用以创建监听
     alter session set container=applicationCreateTest2
      #添加tnsnames.ora文件,新增完成后重启数据库进行加载才会生效
     applicationCreateTest2 =
      (DESCRIPTION =
        (ADDRESS = (PROTOCOL = TCP)(HOST = 数据库原本sid)(PORT = 监听端口号))
        (CONNECT_DATA =
          (SERVER = DEDICATED)
          (SERVICE_NAME = applicationCreateTest2)
        )
      )
      #重新连接数据库进入pdb
      sqlplus / as sysdba
      shutdown immediate
      startup
      alter pluggable database applicationCreateTest2 open;
      alter session set container= applicationCreateTest2
    
    #3、创建测试表空间、测试用户和测试表(c版本创建测试表,建议在表空间用户创建完后通过测试用户名连进来在进行)
      create tablespace wangwang datafile 'E:/12cdbfile/pdbcreatetest_wangwang01.dbf' size 32m;
      create user wangwangTest identified by 123 default tablespace wangwang;
      create table test (id int);
    #4、远程测试用户下,执行下面语句,预计结果为未选定行(无数据) 
      select t.*,
           rowid,
           dbms_rowid.rowid_relative_fno(rowid) 文件,
           dbms_rowid.rowid_block_number(rowid),
           #dbms_utility.make_data_block_address('文件', '块') 数据块地址,
           #dbms_utility.data_block_address_file('数据块地址') 文件,
           #dbms_utility.data_block_address_block('数据块地址') 块,
           rownum,
           dbms_rowid.rowid_row_number(rowid) row_num, -- 等同 rownum
           dbms_rowid.rowid_object(rowid) 对象 -- dba_objects.object_id
      from test t;
    #5、通过insert语句向test中插入数据,然后再次执行4中语句可以看到不同结果
       insert into test values(1);
    
    #行迁移实验-本次实验中任何DML语句执行后必须commit,否则只会是脏数据块不会写入到redo进而存到数据文件中。
    
     #创建一个测试表,插入数据提交
      create table test (id int,name varchar2(4000),job varchar2(2200),sal
    varchar(2000) ) pctfree 0 pctused 99; # pctused标识数据所占的最低百分比,pctfree标识一个块可以保留的空余百分比,0表示全占了。
     insert into test values(1,'dd','xx','sss');
     insert into test values(2,'dx','xx','sss');
     insert into test values(3,'dx','xx','sss');
     insert into test values(4,'dx','xx','sss');
     commit;#必须commit,否则数据是脏块不会写入到表的数据文件中,实验无法开展
     update test set name=RPAD('Z',4000,'Z') where id=4; commit;
     select dbms_rowid.rowid_block_number(rowid) as block_number from test;#查看当前插入表的数据行所持有的块的编号(rowid)
     @E:\app\prince\product\12.1.0\dbhome_1\RDBMS\ADMIN\utlchain.sql;#生成存储被迁移行的块的信息列表chain rows。这个是数据库自带脚本,版本不同位置不同
     analyze table test list chained rows;#开始分析table表
     select * from chained_rows;#查看分析结果,应该是无数据,我们目前没进行行迁移
     update test set job=RPAD('J',2200,'J'),sal=RPAD('S',2000,'S') where
    id=3; commit;#更新数据,范围内随便改就行,可以update多个列,此处只尝试一次行迁移
     analyze table test list chained rows;#重新分析table表
     select owner_name,table_name,head_rowid from chained_rows;#查找已经在header产生链接的块的信息
     select id from test where rowid in (select head_rowid from chained_rows);#查找产生迁移的块的信息 应该是3
     
     #此时已经发生行迁移,但是记录的块号rowid仍然是原来未发生迁移的块的rowid,因为是3的块链接指向迁移目标块,所以我们需要删除这个链接信息,让被链接的块单独独立出来
     create table temp as select * from test where rowid in (select head_rowid
    from chained_rows);#弄一个临时表存一下迁移信息备份
     delete from test where rowid in (select head_rowid from chained_rows);commit;#将发生行迁移的数据行,从测试表中删除
     delete from chained_rows;commit; #需要删掉上一次分析结果然后重新分析
     insert into test select * from temp;commit;#将备份数据插入到表
     
     #上面整个流程其实相当去删掉原来含有链接的块,将发生行迁移的块干掉,链接指向的块直接关联数据库表
     analyze table test list chained rows;#重新分析table表
     select dbms_rowid.rowid_block_number(rowid) as block_number from test;
     #查询表中数据的块的rowid可以看到与第一次查询结果不一样了
    

2、关键配置

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值