• Oracle 数据类型及存储方式(四)


    第四部分 LOB类型
    § 4.1  LOB类型
    4.1.1 LOB类型分类
    CLOB:字符LOB.用于存储大量的文本信息.采用默认字符集存储
    NCLOB:用于存储字符LOB,采用数据库的国家字符集来存储字符.而不是数据库的默认字符集.
    BLOB:二进制LOB,存储二进大量的二进制信息.存储时不会进行字符集转换.
    CLOB和BLOG在ORACLE 10G中可存储8TB字节.
    BFILE:二进制文件LOB,只是一个文件指针.具体的文件存储在操作系统中.
    4.1.2 LOB类型存储方式
    我们把CLOB,NCLOB,BLOB存储在数据库的内部称为内部LOB.这些存储方式都相似,所以可以一起进行讨论.
    SQL> create table test_lob (id int primary key,remark clob);
    Table created
    对于LOB列的创建有非常多的选项.可以查ORACLE文档.
    最简单的就是使用dbms_metadata来获得它的完整的脚本.
    select dbms_metadata.get_ddl('TABLE','TEST_LOB') from dual;
    得到如下结果
      CREATE TABLE "YUAN"."TEST_LOB"
       ( "ID" NUMBER(*,0),
    "REMARK" CLOB,
    PRIMARY KEY ("ID")
      USING INDEX PCTFREE 10 INITRANS 2 MAXTRANS 255
      STORAGE(INITIAL 65536 NEXT 1048576 MINEXTENTS 1 MAXEXTENTS 2147483645
      PCTINCREASE 0 FREELISTS 1 FREELIST GROUPS 1 BUFFER_POOL DEFAULT)
      TABLESPACE "USERS"  ENABLE
       ) PCTFREE 10 PCTUSED 40 INITRANS 1 MAXTRANS 255 NOCOMPRESS LOGGING
      STORAGE(INITIAL 65536 NEXT 1048576 MINEXTENTS 1 MAXEXTENTS 2147483645
      PCTINCREASE 0 FREELISTS 1 FREELIST GROUPS 1 BUFFER_POOL DEFAULT)
      TABLESPACE "USERS"
    LOB ("REMARK") STORE AS (
      TABLESPACE "USERS" ENABLE STORAGE IN ROW CHUNK 8192 PCTVERSION 10
      NOCACHE LOGGING
      STORAGE(INITIAL 65536 NEXT 1048576 MINEXTENTS 1 MAXEXTENTS 2147483645
      PCTINCREASE 0 FREELISTS 1 FREELIST GROUPS 1 BUFFER_POOL DEFAULT))
    LOB列的定义可以有以下属性.
    存储的表空间,本例为USER.也就是说可以为LOB单独指定表空间.
    ENABLE STORAGE IN ROW 默认的一个属性
    CHUNK 属性
    PCTVERSION 属性
    NOCACHE 属性.
    一个完整的STORAGE语句.
    可见,LOB类型之前介绍的数据类型相比要复杂得多了.
    当我们创建了一个带的LOB列的表后,我们可以从USER_SEGMENTS查到,数据库增加了几个段对象.
    SQL> select segment_name,segment_type from user_segments;
    SEGMENT_NAME                      SEGMENT_TYPE
    --------------------------------- ------------------
    BIN$nZwCJWDmQM+ygfB1U8tcIw==$0    TABLE
    BIN$0jfW0nNQR/2JEQmbAmfcRQ==$0    TABLE
    TEST_TIMESTAMP                    TABLE
    TEST_TIMESTAMP2                   TABLE
    TEST_TIMESTAMPWZ                  TABLE
    TEST_TIMELTZ                      TABLE
    TEST_INTERVARYM                   TABLE
    TEST_INTERVALYM2                  TABLE
    TEST_INTERVALDS                   TABLE
    TEST_LOB                          TABLE
    SYS_LOB0000043762C00002$$         LOBSEGMENT
    SYS_IL0000043762C00002$$          LOBINDEX
    SYS_C004324                       INDEX
    后面四个段空间对象.新增了四个物理段.普通表只会新增一个或两个段对象.类型为TABLE和INDEX.
    而LOB列则额外新增了两个段对象,类型为LOBSEGMENT和LOBINDEX.
    SYS_C004324是一个索引段,因为我们有一列为主键.
    作为普通字段,数据就存放在表段中.索引就放在索引段中.
    而对于LOB数据,数据并不是存在表段中,而是存放在LOBSEGMENT段中.(有些情况下是存放在表test_lob中的.后面会讲)
    LOBINDEX用于指向LOB段,找出其中的某一部分.
    所以存储在表中的LOB存储的是一个地址,或者说是一个指针,也可以说是一个LOB定位器(LOB locator).
    存储在LOBindex中的应该是每一个LOB行的地址.数据是具体存储在LOBSEGMENT中的.
    我们先从TEST_LOB的LOB列中找到一个地址,然后在LOBINDEX中来查找这些字节存储在哪里.然后再访问LOBSEGMENT.由此我们可以把lobindex和lobsegment想成是一个主/细表的关系.
    实际上lob列中存的是一个地址段.然后在lobindex找到所有的地址段.然后在lobSegment中把所有地址段的值都读取了来
    4.1.3 LOB类型存储参数介绍
    在此,我们已经基本了解了LOB是怎么存储的.我们也从脚本中看到了LOB类型的参数.现在我们就来了解这些参数
    1. LOB表空间
    LOB ("REMARK") STORE AS (
      TABLESPACE "USERS"
    在test_lob表中的create语句中包含上面的语句.这里指定的表空间指的是存储lobindex 和lobsegment的表空间.也就是说,存放lob数据与LOB列所在的表是可以在不同的表空间的.
    数据表和LOB存放在不同的表空间.
    为什么LOB数据会放在不同的表空间呢?这主要还是管理和性能的问题.
    LOB数据类型代表了非常巨大的容量.在ORACLE 10G之前,LOB列可以存放4GB字节的数据.在ORACLE 10G 中LOB类型可以存放8TB字节的数据.这是非常庞大的数据.
    所以就有必要为LOB数据使用一个单独的表空间,对于备份和恢复以及空间管理.你甚至可以让LOB数据使用另外一个区段大小,而不是普通表数据所用的区段大小.
      另外从I/O性能的角度考虑.LOB是不在缓冲区缓存中进行缓存.因此每个LOB的读写,都会产生物理I/O.正因为如此,如果我们很清楚在实际的用户访问中,有些对象会比大部分其它对象需要花费更多的物理I/O,那么就需要把这些对象分离到其它的磁盘.
    另外,lobindex 和lobsegment是在同一个表空间中的.不可以把lobindex和lobsegment放在不同的表空间中.在oracle 8i之前版本,允许将lobindex和lobsegment放在不同的表空间中.
    2. IN ROW 语句
    LOB ("REMARK") STORE AS (
      TABLESPACE "USERS" ENABLE STORAGE IN ROW
    我们已经了解了LOB类型的存储结构,但是这种结构会带来额外的磁盘访问.不管是读还是写都会比普通数据类型要慢及带来更多的物理I/O.
    针对这种情况,ORALCE作出了个改进就是IN ROW 语句.
    使用ENABLE STORAGE IN ROW从字面上理解就是允许行内存储.当LOB的内容小于4000字节时,就把数据存储在数据表中的,即LOB数据与数据表都是同一个表空间中.这里的LOB就相当于VARCHAR2一样,这里LOB列的数据还可以进入缓冲区进行存储.当LOB内容超过了4000字节后,就会把数据移到lobsegment中去.
    当定义一个LOB列时,它的大小一般都是小于4000字节的,启用IN ROW 是非常重要的.
    如果要禁用IN ROW ,就使用DISALBE STORAGE IN ROW
    3. CHUNK 参数
    LOB ("REMARK") STORE AS (
      TABLESPACE "USERS" ENABLE STORAGE IN ROW CHUNK 8192
    CHUNK 意为大块,块.是指LOB存储的单位.指向LOB数据的索引会指向各个数据块.CHUNK是逻辑上连续的一组数据块.CHUNK是指LOB的最小分配单元.而数据库的最小内存分配单元是数据块(BLOCK).CHUNK大小必须是ORACLE块大小的整数倍.
    我们先来了解一下LOB与CHUNK的关系.
    1. 每一个LOB实例(即每一行的LOB值)会至少占用一个CHUNK.
    用我们本节的数据表test_lob为例,remark列为LOB类型.
    假设该表有1000行数据,每一行的remark列的值大小都为7KB.
    这样数据库就会分配1000个CHUNK.如果CHUNK的大小设置是64KB,就会分配1000个64KB的CHUNK.如果CHUNK的大小为8KB,就分配1000个8KB的CHUNK.
    重要的一点就是一个CHUNK只能由一个LOB对象使用.这有一点像CHAR这种定长类型.如果把CHUNK设为64KB,而实际上我们每一个LOB对象只有7KB的大小,每一列浪费57KB的空间.1000列就浪费了55M的空间.而把CHUNK设为8KB,1000列大约浪费1M的空间.
    我们还知道lobindex,且于指向各个块.它会记录每个块的地址.所以当块越多时,索引就越大,索引越大时,读写就会更慢.整体的性能就会降低.
    比如每个列的LOB字段实际值大约8M,使用8KB的CHUNK.那么就需要1024个CHUNK.那么在lobindex中就会有1024条记录,用来指向这些CHUNK.
    指定CHUNK值,影响到性能和空间.
    如果CHUNK过大,就会白白浪费存储空间,如果CHUNK过小,就会降低性能.
    所以我们需要在空间和性能上进行取舍和折中.
    4. PCTVERSION 语句
    LOB ("REMARK") STORE AS (
      TABLESPACE "USERS" ENABLE STORAGE IN ROW CHUNK 8192 PCTVERSION 10
    PCTVERSION用于控制LOB的读一致性.普通字段都会有UNDO记录的.而lobsegment是没有undo记录的.而是直接在lobsegment本身中维护停息的版本.lobindex会像其它段一样生成undo记录.但是lobsegment不会.
    修改一个LOB对象时,oracle会分配一个新的CHUNK,而来的CHUNK会被保留下来.如果事务正常的提交了,lobindex就像指向新的CHUNK.如果事务被回滚了,lobindex就再指回原来的CHUNK.所以undo维护是在LOB段自身中实现的.
    这样一来,就会有非常多的无用的CHUNK被开销了.这也是非常大的空间损耗.这些CHUNK指的是数据的旧版本信息.那如何来控制这些旧版本数据占用的空间呢?这就是PCTVERSION的作用.也就是说用多少额外的空间来存储旧版本数据.我们可以看到默认的值是10%.如果你确实经常修改LOB,那么就需要把它设为10%就不够了,需要增加这个值.
    5. CACHE参数
    LOB ("REMARK") STORE AS (
      TABLESPACE "USERS" ENABLE STORAGE IN ROW CHUNK 8192 PCTVERSION 10
      NOCACHE
    除了NOCACHE外,这个选项还可是CACHE和CACHE READS.这个参数控制lobsegment数据是否存储在缓冲区的缓存中.默认为NOCACHE,也就是每次访问都是从磁盘直接读取写.
    CACHE READS允许缓存从磁盘读的LOB数据.但是写入LOB数据是直接写进磁盘的.
    CACHE则是允许读和写都能缓存LOB数据.
    有些情况下,LOB字段只有几KB大小,进行缓存就非常有用了.如果不缓存,当用户更新LOB字段时,还必须进行等待,从磁盘直接读数据和写数据.
    如果要修改缓存设置可以用下面的语句
    ALTER TABLE test_lob modify LOB(remark) (CACHE);
    ALTER TABLE test_lob modify LOB(remark) (NOCACHE);
    ALTER TABLE test_lob modify LOB(remark) (CACHEREADS);
    但是对于大数据量的LOB读写,比如超过了20M.是没有理由把它放进缓存的
    § 4.2 BFILE
      BFILE类型只是操作系统上一个文件的指针.用于对存储在操作系统中的文件提供只读访问.
    使用BFILE时,还可以使用一个DIRECTORY 对象.DIRECTORY 是将一个操作系统目录映射到数据库的一个串.以便于提供可移值性.
    SQL> create table test_bfile(id int primary key, moviefile bfile);
    Table created
    SQL> create or replace directory movie_directory as 'D:/movie';
    Directory created
    SQL> insert into test_bfile values(1,bfilename('movie_directory','英雄.dat'));
    1 row inserted
    对BFILE的操作需要使用DBMS_LOB包来进行.提供了一系统方法和函数

  • 相关阅读:
    cocos2d-x避免手动修改android.mk文件来编译
    Android.mk详解
    cocos2dx 安卓编译问题收集
    Mac下部署Android开发环境附加NDK
    SpringMVC关于json、xml自动转换的原理研究
    SpringMVC的拦截器
    Spring3中的mvc:interceptors标签配置拦截器
    Spring常用的接口和类(三)
    Spring常用的接口和类(二)
    LeetCode:寻找旋转排序数组中的最小值【153】
  • 原文地址:https://www.cnblogs.com/itelite/p/2311174.html
Copyright © 2020-2023  润新知