总体印象,这本书本身就写得浅显易懂,例子也多,基本上性能比较都在书中列出,节约了读者时间,看完数据库,要结合一个实例来分析的话,是很好的选择。另外,翻译得也很从不错,没有很晦涩的地方,读下来,不需要参照电子版的英文版,翻译得如此,确实是值这个价,虽然这本书是我借图书馆的,而且因为太大,所以多拖了一个多星期才还,虽然还是很多部分看得不是很仔细….
第1章 开发成功的Oracle应用
信守的思想:
l 如果可能,尽量以用一条SQL完成工作
l 如果无法用一SQL完成,通过PL/SQL完成
l 如果PL/SQL无法完成,使用Java存储过程实现
l 如果Java办不到,那就用C外部过程中实现。如果速度要求高,或使用C的第三方API。
l 如C外部例程中无法实现,就该好好想想有没有必要做这个工作。
正确方法
l 在Oracle中使用一个连接,而不是像SQL Server那样,每条执行的并发语句都打开数据库连接。
l 使用绑定变量,在Java中即PrepareStatement.
l 理解并发控制,防止更新丢失
数据库的独立性
标准的影响,SQL
防御式编程,sequence,利用触发器插入主键,插入时,为主键插入sequence.NEXTVAL
开放性,作者认为,不遗余力地争取数据库的独立性和完全的开放性是一个错误的决定,不管什么数据库,都应该充分利用,把它的每一个功能都挤出来。
第2章 体系结构概述
数据库和实例的区别
数据库:物理操作系统文件或磁盘集合。
实例:一组Oralce后台进程以及一个共享内存区。由同一个计算机运行的线程、进程所共享。但集群时,是多个实例同时装载并打开一个数据库。
重申:
实例是一组后台进程和共享内存
数据库是磁盘上存储的数据集合
实例一生只能装载并打开一个数据库
数据库可以用一个或者多个实例(使用RAC)装载并打开,Real Application Clusters 实时应用集群
连接Oracle
专用服务器
共享服务器,由调度器处理请求队列和响应队列
TCP/IP连接的基本原理。TNS代表Transparent Network Substrate。[Oracle_Home]/network/admin下配置
TNS监听器,可以建立专用(fork/exec)或共享服务器(给调度器)
第3章 文件
看得不是很仔细
参数文件:v$parameter Table,遗留的inti.ora参数文件
数据文件
段segment 占用存储空间的数据库对象,如回滚段,临时段,聚簇段,索引段
区段 extent 段本身由一个或多个区段组成。它是文件中一个逻辑上连续分配的空间。
块 block 区段由块组成。Oracle最小的空间分配单位。默认大小:2/4/8/16KB,如操作系统允许,可有32KB的块大小。只有创建数据库指定非标准块大小(非2次幂),才会有6种块大小。故,一般5种。
块结构
l 首部
l 表目录
l 行目录
l 空闲空间
l 数据
l 尾部
表空间 table space 包含段。段绝对不会跨越表空间边界。表空间本身可有一个或多个相关数据文件。而其中一个区段extent在一个数据文件中。但段可以来自多个不同数据文件的区段。
总结:从大到小,表空间、段、区段、块
重做日志文件
每个Oracle数据库都至少有两个在线重做日志文件组。每个日志组都包含一个或多个重做日志成员。
在填满日志文件1并切换到日志文件2时,Oracle会启动一个检查点。data block writer就会把日志文件组1保护的脏块写入磁盘。
第4章 Oracle内存结构
看得不是很仔细
PGA Process Global Area
分为: *_AREA_SIZE, 例如SORT, HASH等操作
PGA是进程专用内存区,专用或共享服务器需要的一组独立于会话的变量。
UGA USER GLOBAL AREA
共享服务器,在SGA中分配;专用服务器,在PGA中分配
SGA System Global Area
分为:共享池、Java池、大池、流池、空池
共享池:Oracle缓存一些“程序”数据的地方,在解析一个查询时,解析得到的表示就缓存在这里。因此,运行的PL/SQL代码就在共享池中缓存,下一次运行时,Oracle不会再次从磁盘中读取。代码在这里共享和缓存。
破坏共享区原因:
l 大量CPU时间解析查询,即没有绑定变量
l 大量资源来管理共享池中对象,从来不重用查询
大池:用于大块内存的分配,共享池不会处理这么大的内存块。
主要用于以下情况:
共享服务器连接:在SGA中分配UGA
语句的并行执行
备份:用于RMAN磁盘I/O缓冲区
Java池:
Oracle 8 后增加的,在数据库中运行Java。如果Java编写存储过程,Oracle会在处理代码时使用Java池的内存。
流池: 10g 开始增加,共享/复制工具。
第5章 Oracle进程
看得不是很仔细
Oracle中的进程,在某些操作系统中,如windows,Oracle用线程实现,因此这里要把所说的“进程”理解为“线程”的同义词。而Unix下的Oracle是多进程实现,“进程”就很贴切。
连接与会话
连接connection就是客户进程与Oracle实例间的一条物理路径,如一个网络连接。会话是数据库的一个逻辑实体。客户进程在会话上执行SQL,多个独立会话可以与一个连接相关联。
专用服务器下,客户连接和服务器进程之间有一个一对一的映射。共享服务器中,客户应用会连接到Oracle TNS监听器上,并重定向或转交给一个调度器。客户应用会与一个调度其进程物理连接。
一般来说,Disconnect命令 = Destroy all sessions, 断开连接要用exit命令,而connect命令=create session
第6章 锁
锁定问题
丢失更新
悲观锁定:pessimistic locking select … for update (nowait).
乐观锁定:Oracle实现由三种方法:
l 使用一个特殊的列,此列由触发器或应用程序代码维护,可以告诉我们记录的“版本”
l 使用一个校验或散列值,这是由原来数据计算得出的
l 使用Oracle 10g 特性ORA_ROWSCN,默认情况下,ORA_ROWSCN序号以块为单位推进,定义table时,需要加上ROWDEPENDENCIES来表示行独立性。其为内置特性,由Oracle自动执行,不需要在表中增加额外的列,也不需要额外的更新/维护代码来更新这个值。
DML锁、DDL锁,原来写过文章,不再详述。《Oracle中的并发控制.doc》
闩
轻量级的串行化设备,用于协调对共享数据结构、对象和文件的多用户访问。
闩“自旋”
解析SQL语句时,会为共享池中的库缓存和相关结构得到并释放数百个或数千个闩。等待闩可能是一个代价很高的操作。自旋是指在循环中反复等待尝试得到闩,这样实现是因为上下文切换的开销很大。如果进程不能立即得到闩,会一直呆在CPU上,并立即再次尝试,而不是先休眠,放弃CPU。如果自旋,但之后还是得不到闩,此时进程才会休眠。
第7章 并发与多版本
《Oracle中的并发控制.doc》
写一致性
Oracle提供了读一致性,考虑:update t set x=2 where y = 5;
在该语句运行时,有人将整条语句已经读取得一行从y=5更新为y=6. 即这句通过一致性读时,y=5,但现在y的当前值为6.更新会如何?即写一致性问题,这是多版本的数据库所特有的问题。
Oracle处理修改语句会完成两类块获取,会执行:
一致读:发现要修改的行时,所完成的获取就是一致读。
当前读:得到块来完成更新所需要修改的行时,所完成的获取就是当前读。
例子
select * from t
update t t1 set x=x+1
update t t1 set x=x+1
select没有当前读,第一个update会比select多3个当前读,它们是获得要更新的块,获得undo段块,获得undo块。第二个update只有1个当前读,只要获得要更新的块,因为这三句是同一个事务,不需再完成撤销工作。
重启动例子:
事务1 事务2
update t set y=10 where y =5
update t set x=x+1 where y=5
commit.
这就是当前读的作用,事务2中,原来y=5的记录可能不再是5,这种情况下,事务2会选择重启动更新。
重启动的影响:
注意:触发器也会导致重启动,例如用:old/:new来使用数据时,Oracle发现其中有值与原来不一致时,就会从启动;而如果不引用时,就不会重启动。
如果一个批量更新,100,000行更新后,发生重启动,需要回滚100,000行数据,很大影响性能.
解决方法:解除触发器的所有非事务性工作,使之在事后的作业中完成.
第8章 事务
语句/过程原子性和事务原子性
过程中只要不捕获异常,Oracle遇到过程中有异常,就会回滚过程.
事务的 IMMEDIATE 约束和 DEFERRABLE约束,即语句时检查还是提交时才检查.
不好的事务习惯
l 循环中提交.
l 使用自动提交. Java中的 JDBC默认是自动提交,应该默认为conn.setAutoCommit(false);
自治事务
如果一个”正常”的过程中commit, 它不仅会持久保留自己的工作,也会使该会话未完成的工作成为持久性的。不过如果在一个自治事务中完成提交,只会让这个过程本身的工作成为永久性的。
书中有一个使用自治事务,AUDIT审计的例子,如果用触发器实现此功能,能检查到update,而且发现非法时,会记录,而且让update失败,但触发器失败时,也会使自己回滚。故要使用自治事务。在触发器中有一个自治事务。
第9章 redo 与 undo
看得不仔细
修改数据库中的数据时,会发生以下操作:
l 已经在SGA中生成了Undo块。
l 已经在SGA中生成了已修改的数据块
l 已经在SGA中生成了前两相对应的缓存redo
l 取决于前三项大小,以及工作花费的时间,前面的某个数据可能已经输出到磁盘
l 已经得到所需的全部锁
commit时,余下的工作是:
l 为事务生成一个SCN
l LGWR将所余下的缓存重做日志写至磁盘,并且把SCN记录到在线重做日志中。真正的commit,如果出现这一步,即已经提交。事务条目会从V$TRANSACTION中“删除”,说明我们已经提交。
l V$LOCK中记录着我们会话中持有的锁,这些锁都会被释放,而排队等待这些锁的,会被唤醒
l 如果事务修改的某些块还在缓冲区缓存中,则会以一种快速的模式访问并“清理”。
rollback时,会做的工作:
l 撤销已做的所有修改。从undo段读会数据,然后实际上逆向执行前面所作的操作,并将undo条标记为已用。
l 释放所有锁。唤醒相关工作。
日志竞争
常见原因:
redo放在一个慢速设备上
redo与其它频繁访问的文件放在同一个设备上
以缓冲方式装载日志设备
redo使用一种慢速技术,例如RAID5,其适合读,但写时性能很差。
第10章 数据库表
看得不仔细
术语: 段、段空间管理、高水位线、freelists、PCTFREE和PCTUSED、LOGGING和NOLOGGING、INITRANS和MAXTRANS
堆组织表
索引组织表
索引聚簇表
聚簇表的概念和聚簇索引、非聚簇索引概念不同。
聚簇索引是物理位置按照索引键的值顺序排列。
非聚处索引,只是一个键值对,与数据物理位置没有关系。
散列聚簇表
有序散列聚簇表
嵌套表
临时表
对象表
第11章 索引
B*数索引
索引键压缩
在建立索引时,执行压缩类型,压缩带来的大小变化不是免费的,会花更多的话时间处理这个索引结构中的数据,不光在修改期间花费时间,查询期间也花更多时间。
反向键索引
使用RESERVE关键字
例子dump(90101,16)为c3,a,2,2;dump(90102,16)为c3,a,2,3
dump(reserve(90101),16)为2,2,a,c3;dump(reserve(90102),16)为3,2,a,c3
可以看到这样做数据之间会“相距很远”,这样在RAC应用,集群应用中,访问同一个块的RAC实例个数就能减少。反向索引的缺点之一是:能用常规索引的地方不一定能用反向索引。例如where x > 5;
如果在x,y中用反向索引,Oracle会存储(RESERVE(X)||RESERVE(Y)),而不是(RESERVE(X||Y))。因此X=5的查询有效。
反向索引有助于缓解缓冲区忙等待问题,但是取决于其他的一些因素。通过消除缓冲区忙等待,将对事务吞吐量稍有影响,同时随着并发度增加,反向索引可扩展性会增加。
降序索引
8i开始引入,用以扩展B*树索引的功能。它允许在索引中以降序而不是升序存储。
例如
create index desc_t idx on(owner desc, object_type asc)
这样在查询相同顺序的时候,可以直接利用索引,比起一般的索引会少一步sort操作。
使用索引的两种方法:
索引用于访问表中的行:希望你访问表中很少的一部分行。
索引用于回答一个查询:包含了足够的信息回答整个查询。
书中给出例子,物理组织对查询结构的影响,相同数据,相同的索引,就是物理组织不一致,一个是共同放置(co-located)和无组织(disorganized),都采用索引查询,性能差异很大。
结果还表明,对于物理块较分散的情况,做一次全表搜索反而效率更高。优化器会自己选择最优方案。
聚簇因子
之前的问题,引出聚簇因子的概念,可以把聚簇因子看作是通过索引读取整个表时对表执行的逻辑I/O次数。越低说明越聚簇。上面的例子中,聚簇因子在user_indexes.clustering_factor查出,刚刚的例子聚簇相差近100倍!
以上的关键点是,索引并不一定总是合适的访问方法,优化器也许选择不使用索引,而且这种选择可能是正确的。
位图索引
位图索引对于相异基数(distinct cardinality)低的数据最为合适。位图索引在读密集的环境中能很好地工作,但是对于写密集的环境则极不适用。原因在于,一个位图索引条目指向多行,修改所索引条目时,大多数情况下,会锁定整个位图索引条目。
位图联结索引
create bitmap index emp_bm_idx
on emp(d.dname)
from emp e, dept p
where e.deptno = d.deptno
这样对于select count(*) from emp, dept where emp.deptno=dept.deptno and dept.dname=”SALES”
的查询,不需要真正的访问EMP表或DEPT表,答案来自索引本身。
基于函数的索引
必须是DETERMINISTIC的函数才可以用来建立索引,即给定相同输入时,输出都是相同的。
只对部分行建立索引
create index processed_flag_idx on big_table(case temporary when ‘N’ then ‘N’ end)
实现有选择的唯一性,基本上同“只对部分行建立索引”
重写case,使索引在某些查询时不可用。
使用DECODE而不是CASE,因DECOEDE不会被重写。
对于to_char(to_date(‘2005’ ‘YYYY’),’DD-MON-YYYY HH24:MI:SS’)方法,不同月份会得到不同结果,因此不算DETERMINISTIC,不能用于创建索引。
关于索引的常见问题和神话
视图能适用索引吗?
其实还是对基表建立索引
NULL能和索引协作吗?
只有所有条目都为NULL的条目才会被索引忽略。例子:
create table t (x int, y int)
create unique index t_idx on t(x,y)
insert into t values(NULL,NULL)
insert into t values(1,NULL)
insert into t values(NULL,1)
而insert into t values(NULL,NULL)可以再执行,原因不认为是新的(NULL,NULL)与旧的相同。这是Oracle实现,也是SQL标准要求的。
不过对于聚簇操作,(NULL,NULL)和(NULL,NULL)则认为是相同的。
如 select x, y, count(*) from t group x, y having count(*)>1
结果,因为其他都是1。重复执行insert into t values(NULL,NULL),只有NULL,NULL为2个
X Y COUNT(*)
2
外键是否应该加索引?
因为表锁的关系,当外键上没还有索引,修改父表的主键或者删除记录时,会对子表加表锁,使得效率很低,故一般都要为外键加索引。
如果满足以下条件则可以不需要加:
未删除父表中的行。
不论是有意还是无意,总之未更新父表中的唯一/主键值。
不会从父表联结到子表,或者更一般地说,外键列不支持子表的一个重要的访问路径,而且你在谓词中没有使用这些外键列从子表中选择数据。即
select * from dept, emp where emp.deptno = dept.deptno and dept.dname=:X
emp为子表,dept为父表
为什么没有使用我的索引?
情况1
使用一个B*索引,而且谓词中没有使用索引的最前列。例如对T(x,y)建立索引,用select * from t where y=5,优化器不打算使用索引,优化器通常会选择对T做一次全表扫描。但并不排除使用索引。
如果查询是Select x, y from t where y=5,优化器会注意到,对索引本身做一次扫描更合适。
另一情况下CBO使用(x,y)上的索引,这就是索引跳跃式扫描。当且仅当索引最前列只有很少的几个值。
这样的索引是,先按x做一次索引,然后对相同x下的y再做一次索引。因为,第一列值少,导致第一列的树结点少,很快就可以到第二列的索引排序。
情况2
select count(*) from T ,避免导致错误结果,因为有全NULL的条目
情况3
select * from t where f(index_column) = value
索引是在index_column上,而不是F(index)上
情况4
对一个字符列建立了索引,但这个列只有数值数据,例如select * from t where indexed_column = 5,indexed_column是字符列。
因系统隐式调用to_number(indexed_column),因此情况类似于情况3。
优化技巧:
在函数上建立索引
改变SQL查询方式
如
select * from t where trunc(data_col) = trunc(sysdate);
可以变为:
select * from t where data_col >= trunc(sysdate) and data_col< trunc(sysdate+1)
这样就可以用data_col的索引了。
情况5
如果此时使用索引,实际上反而更慢,例如之前的物理组织影响的例子。
情况6
有一段时间没有分析表,这些表起先很小,等查看时,已经增长得很大,现在索引才有意义,如果没有正确的统计信息,CBO无法做出正确的决定。
神话:索引中从不重用空间
神话:最有差别的元素应该在最前面
经过Oracle的优化,按照各个列的差别大小来排列这些猎在索引中的顺序并不会获得本质上的效率提升。书中例子证明了这点,在Oracle中应该根据应用查询的具体情况,决定索引的创建情况
例如:
系统中有大量如下查询:
select * from t where c1 = x where c2=y
select * from t where c2=y
这样的话,创建(c2,c1)索引更合适,以上两个查询都能用到这个索引。
第12章 数据类型
CHAR:定长字符串,会用空格填充达到其最大长度,最多2000字节,CHAR(10)除NULL,总10字节
NCHAR:包含UNICODE格式数据的定长字符串,最多2000字节,注意NCHAR(10)除NULL,总10字符
VARCHAR2:变长字符串,不会填充,最多4000字节,数字表示字节
NVARCHAR2:变长字符串,不会填充,最多4000字节,类似CHAR和NCHAR的区别,数字表示字符
RAW:变长二进制数据结构,最多2000字节
NUMBER:最多达38位数字,长度在0-22字节之间,精度很高,远高于多数编程语言的FLOAT和DOUBLE
BINARY_FLOAT: 10g 以后的新类型。32位单精度浮点数,至少6位精度
BINARY_DOUBLE:新类型。64位双精度,至少13位精度
LONG:最多2GB的字符数据,只是向前兼容,应该用CLOB类型
LONG_RAW,只是向前兼容,应该用BLOB类型
DATE:这是7字节的定宽日期/时间数据结构,精确到秒
TIMESTAMP:7或者11字节的定宽日期/时间数据结构,与DATE不同,TIMESTAMP精确到小数秒,带小数的秒最多保留9位
TIMESTAMP WITH TIME ZONE:类似前一种,13字节,存储额外的关于时区信息
TIMESTAMP WITH LOCAL TIME ZONE:7或者11字节,对时区敏感。如你想使用US/Pacific时区,而数据库时区为US/Eastern,那获得的时间会被转换为Eastern,再像TIMESTAMP那样存储。
INTERVAL YEAR TO MONTH:5字节定宽数据类型。这个类型将时段存储为年数和月数。可以使用这种时间间隔使一个DATE或TIMESTAMP类型增加或减少一段时间。
INTERVAL DAY TO SECOND:11字节,一个时段,天/小时/分钟/秒数,最多9位小数秒。
BFILE:存储一个Oracle目录对象和一个文件名,并读取这个文件。实际上允许你以只读方式访问数据库服务器上可用的操作系统系统文件。
BLOB:9i和以前的版本中,可存储最多4GB字节数据。 10g 后允许4*数据库块大小 GB,适合存储电子表格、字处理文档、图像文件等。
CLOB:包含要进行字符集转换的信息,适合纯文本信息
NCLOB:类似CLOB,存储用数据库国家字符集编码信息,这些信息需要进行字符集转换。
ROWID:实际上是数据库中一行的10字节地址。足以在磁盘上定位这一行,以及标示ROWID指向的对象(表等)
UROWID:通用的ROWID,用于表。UROWID是行主键值的一种表示,因此,取决于所指向的对象,UROWID的大小会有所变化。
以上不全,如INT/SMALLINT/FLOAT等,这些类型实际是所列基本类型的基础上实现的。XMLTYPE等复杂类型也没有列出。
字符和二进制串类型
字符串编码NLS_CHARACTERSET
二进制RAW
每个二进制字节都显示为两个十六进制字符。因此看上去似乎超过其指定的长度,记住,显示的是16进制
NUMBER
NUMBER(p,s)
精度,合法取值为 1 - 38
小数位,合法取值为 -84 - 127
对于超精度的情况,报错提示
对于超小数位的情况,用舍入法解决。
小数位的负数表示精确到小数点往前数多少位,例如,-2位精确到100,十位个位将被舍入。
书中介绍处理遗留的LONG类型,不详述
日期类型
用 trunc(data_col, ‘y’) = to_date(’01-Jan -2005’ ,’dd-mm-yyyy’)
代替 to_char(date_col,’yyyy’) = ‘2005’
可以有性能上的优势,两者大概相差10倍左右。原因是,to_char把日期转换为字符串,有更长的代码路径,而trunc则是修改日期格式的字节,相当于mask。因此,应该尽量用trunc 代替 to_char进行日期截断。
向日期增加和减少时间:
常用的三种方法
l 向DATE 增加一 NUMBER,例如加1,就是增加1天,1/24就是1小时。
l 用INTERVAL类型增加时间单位,两种粒度:年和月,或日/小时/分钟/秒。
l 使用内置的ADD_MONTH函数增加月
TOM的建议:
l 使用NUMTODSINTERVAL内置函数增加小时、分钟和秒,使用方法NUMTODSINTERVAL (1,’second’),增加1秒;NUMTODSINTERVAL (1,’hour),增加1小时
l 加一个简单的数来增加天
l 使用ADD_MONTH内置函数增加月和年
不建议使用NUMTOYMINTERVAL函数,其原因与这个函数如何处理月末日期有关。
ADD_MONTH实际上会为我们完成日期的“舍入”。如31日的增加一个月,而且下个月不足31天,会返回下个月的最后一天。另外,向一个月的最后一天增加1个月会得到下一个月的最后1天。如平年2月28变3月31。
而NUMTOYMINTERVAL则可能会报出非法日期的信息。
得到两个日期的差
使用MONTHS_BETWEEN内置函数将这个数转换为年数和月数。另外,使用trunc得到两个日期间隔月数中整数部分,再使用add_months内置函数将dt1 增加12个月。再从两个日期中较大者,减去这个计算的得到的日期,从而得到两个日期之间的天数和小时数
select numtoyminterval(months_between(dt2,dt1),’month’) years_months,
numtodsinterval(dt2 – addmonths(dt1, trunc(months_between(dt2,dt1))), ‘day’) days_hours
from (select to_date(’29-feb -2000 01:02: 03’ , ‘dd-mon-yyyy hh24:mi:ss’) dt1,
select to_date(’15-mar-2000 01:02: 03’ , ‘dd-mon-yyyy hh24:mi:ss’) dt2
from dual )
结果:
1年、15天、10小时、20分钟、30秒
TIMESTAMP,指定小数位个数。
得到两个 TIMESTAMP之差,DATE和TIMESTAMP的最显著差别,DATE相减是一个NUMBER,但TIMESTAMP相减结果是一个INTERVAL:
类似上边,只是不需要,numtodsinterval函数,但问题是,这样会丢失小数秒。作者认为,显示有年和月的信息时,TIMESTAMP的真实性已经被破坏,一年本身的长度就不一定,如果有年月信息,毫秒级的损失是可以接受的。
INTERVAL YEAR(n) TO MONTH
n可为0 – 9,默认2。
创建5年2月的时间间隔
select numtoyminterval(5,’year’) + numtoyminterval(2, ‘month’) from dual
INTERVAL DAY(n) TO SECOND(m)
n可为0 – 9,默认2。m可为0 – 9,默认6。
创建方法类似,用numtodsinterval
LOB类型
表中的LOB实际上只是指向lobindex,lobindex再指向LOB本身的各部分。为了得到LOB中的N到M字节,要对表中的指针(LOB定位器)解除引用,遍历lobindex结构来找到所需的数据块(chunk),然后顺叙访问。这使得随机访问LOB的任何部分都能同样迅速,无需从头遍历。
Table 到 lobindex 到LobSegement.
Oracle8开始,不允许lobindex和LobSegmentb不在同一个表空间中。对于小于4000字节的LOB,可能内联,或者存储在表中,这种情况下,LOB数据会被缓存。
IN ROW子句
控制LOB数据是否总与表分开存储(存储在LobSegment中),或是有时可以与表同一存储,而不放在logSegmentz中。lob(in_row ) store as (enable storage in row) 可用disable禁用。
chunk是LOB的最小分配单元。而通常数据库的最小分配单元是块。
每个LOB实例(每个行外存储的LOB值)会占用至少一个CHUNK。一个CHUNK由一个LOB值使用。
另外,注意要让每个LOB实例对应的CHUNK数减至最少。主要是减小lobindex的索引出数。
PCTVERSION LOB读一致性
RETENTION 与PCTVERSION互斥,要求数据库使用自动undo管理
CACHE 控制数据是否存储在缓冲区中
ROWID/UROWID类型
原来ROWID的行是不变的,插入时创建,直到删除。但后来情况有改变,有可能使ROWID改变,例如:
l 在分区表中更新一行的分区键,使这一行必须从一个分区移至另一分区
l 使用FLASHBACK TABLE命令将一个数据库表恢复到以前的某个时间点
l 执行MOVE操作以及许多分区操作,如分解或合并分区
l 使用ALERT TABLE SHRINK SPACE命令执行段收缩
以下部分看得不是很认真,略
第13章 分区
第14章 并行执行
第15章 数据加载和卸载