索引组织表(Index Organizied Table)

索引组织表(index organized table, IOT)就是存储在一个索引结构中的表。存储在堆中的表是无组织的(也就是说,只要有可用的空间,数据可以放在任何地方),IOT中的数据则按主键存储和排序。对你的应用来说,IOT表和一个“常规”表并无二致。

索引组织表的数据按主键排序手段被存储在B-树索引中,除了存储主键列值外还存储非键列的值。普通索引只存储索引列,而索引组织表则存储表的所有列的值。

索引组织表一般适应于静态表,且查询多以主键列。当表的大部分列当作主键列时,且表相对静态,比较适合创建索引组织表!(8i以上)

既然它属于表,那么它当然也有建立索引的需求。由于它的索引的结构,比如说由于索引叶节点的分裂,行所在块可能会发生改变,因而建立在IOT上的索引和一般的索引的最大区别是它存的是IOT的行的逻辑地址,也就是UROWID,oracle用这个逻辑rowid来猜这个行所在的块,如果猜到了,那么这个urowid是正确的,否则它从这个地址向下遍历来找这条记录。

IOT表的rowid是逻辑上的,因为IOT表中的行的位置是在不断变化的(例如插入新的行,有可能带来其它行的位置移动)

    IOT有什么意义呢?使用堆组织表时,我们必须为表和表主键上的索引分别留出空间。而IOT不存在主键的空间开销,因为索引就是数据,数据就是索引,二者已经合二为一。但是,IOT带来的好处并不止于节约了磁盘空间的占用,更重要的是大幅度降低了I/O,减少了访问缓冲区缓存(尽管从缓冲区缓存获取数据比从硬盘读要快得多,但缓冲区缓存并不免费,而且也绝对不是廉价的。每个缓冲区缓存获取都需要缓冲区缓存的多个闩,而闩是串行化设备,会限制应用的扩展能力)

IOT适用的场合有:
1、完全由主键组成的表。这样的表如果采用堆组织表,则表本身完全是多余的开销,因为所有的数据全部同样也保存在索引里,此时,堆表是没用的。
2、代码查找表。如果你只会通过一个主键来访问一个表,这个表就非常适合实现为IOT.
3、如果你想保证数据存储在某个位置上,或者希望数据以某种特定的顺序物理存储,IOT就是一种合适的结构。

    IOT提供如下的好处:
·提高缓冲区缓存效率,因为给定查询在缓存中需要的块更少。
·减少缓冲区缓存访问,这会改善可扩缩性。
·获取数据的工作总量更少,因为获取数据更快。
·每个查询完成的物理I/O更少,因为对于任何给定的查询,需要的块更少,而且对地址记录的一个物理 I/O 很可能可以获取所有地址(而不只是其中一个地址,但堆表实现就只是获取一个地址)

    如果经常在一个主键或惟一键上使用BETWEEN 查询也是如此,因为相近的记录存在一起,查询时引入的逻辑IO和物理IO都会更少。

索引组织表的详细参数

ops$tkyte@ORA10GR1> select dbms_metadata.get_ddl( 'TABLE', 'T1' ) from dual;

S_METADATA.GET_DDL('TABLE','T1')

-----------------------------------------------------------------------------

CREATE TABLE "OPS$TKYTE"."T1"

"X" NUMBER(*,0),

"Y" VARCHAR2(25),

"Z" DATE,

PRIMARY KEY ("X") ENABLE

ANIZATION INDEX

OMPRESS

PCTFREE 10 INITRANS 2 MAXTRANS 255 LOGGING

STORAGE(INITIAL 65536 NEXT 1048576 MINEXTENTS 1 MAXEXTENTS 2147483645

PCTINCREASE 0 FREELISTS 1 FREELIST GROUPS 1 BUFFER_POOL DEFAULT)

TABLESPACE "USERS"

PCTTHRESHOLD 50

NOCOMPRESS 选项

这个选项对索引一般都可用。它告诉 Oracle 把每个值分别存储在各个索引条目中(也就是不压缩)。如果对象的主键在 A、B 和 C 列上, A、B 和 C 的每一次出现都会物理地存储。 NOCOMPRESS 反过来就是 COMPRESS N ,在此 N 是一个整数,表示要压缩的列数。这样可以避免重复值,并在块级提取 “公因子”( factor out )。这样在 A 的值(以及 B 的值)重复出现时,将不再物理地存储它们。

下面做一个快速的测试,对前面 CREATE TABLE 的 SELECT 分别采用 NOCOMPRESS 、 COMPRESS 1 和COMPRESS 2 选项,来展示能节省多少空间。先来创建 IOT ,但不进行压缩:

ops$tkyte@ORA10GR1> create table iot

2 ( owner, object_type, object_name,

3 constraint iot_pk primary key(owner,object_type,object_name)

4 )

5 organization index

6 NOCOMPRESS

7 as

8 select distinct owner, object_type, object_name

9 from all_objects

10 /

tablle created.

现在可以测量所用的空间。为此我们将使用 ANALYZE INDEX VALIDATE STRUCTURE 命令。这个命令会填写一个名为 INDEX_STATS 的动态性能视图,其中最多只包含一行,即这个 ANALYZE 命令最后一次执行的信息:

ops$tkyte@ORA10GR1> analyze index iot_pk validate structure;

index analyzed.

ops$tkyte@ORA10GR1> select lf_blks, br_blks, used_space,

2 opt_cmpr_count, opt_cmpr_pctsave

3 from index_stats;

LF_BLKS  BR_BLKS  USED_SPACE  OPT_CMPR_COUNT  OPT_CMPR_PCTSAVE

284  3  2037248 2 33

由此显示出,我们的索引目前使用了 284 个叶子块(即数据所在的块),并使用了 3 个分支块( Oracle在索引结构中导航所用的块)来找到这些叶子块。使用的空间大约是 2MB (2,038,248 字节)。另外两列名字有些奇怪,这两列是要告诉我们一些信息。 OPT_CMPR_COUNT (最优压缩数)列要说的是:“ 如果你把这个索引置为 COMPRESS 2 ,就会得到最佳的压缩 ” 。 OPT_CMPR_PCTSAVE (最优的节省压缩百分比)则是说 ,如果执行 COMPRESS 2 ,就能节省大约 1/3 的存储空间,索引只会使用现在 2 /3 的磁盘空间。

下面用COMPRESS 2进行压缩:

ops$tkyte@ORA10GR1> alter table iot move compress 2;
Table altered.

ops$tkyte@ORA10GR1> analyze index iot_pk validate structure;

Index analyzed.

ops$tkyte@ORA10GR1> select lf_blks, br_blks, used_space,

2 opt_cmpr_count, opt_cmpr_pctsave

3 from index_stats;

LF_BLKS  BR_BLKS  USED_SPACE  OPT_CMPR_COUNT  OPT_CMPR_PCTSAVE

190  1  1359357 2 0

现在大小有了显著减少,不论是叶子块数还是总的使用空间都大幅下降。
(关于这个参数的详细说明参见第十一章 索引 11.2.1借 索引键压缩 )

OVERFLOW&PCTTHRESHOLD&INCLUDING选项

OVERFLOW 子句允许你建立另一个段(这就使得 IOT 成为一个多段对象,就像有一个 CLOB 列一样),如果 IOT 的行数据变得太大,就可以溢出到这个段中。

注意:构成主键的列不能溢出,它们必须直接放在叶子块上。

PCTTHRESHOLD :行中的数据量超过块的这个百分比时,行中余下的列将存储在溢出段中。所以,如果 PCTTHRESHOLD 是 10% ,而块大小是 8KB ,长度大于 800 字节的行就会把其中一部分存储在别处,而不能在索引块上存储。

INCLUDING :行中从第一列直到 INCLUDING 子句所指定列(也包括这一列)的所有列都存储在索引块上,余下的列存储在溢出段中。

对于 IOT 最后要考虑的是建立索引。 IOT 本身可以有一个索引,就像在索引之上再加索引,这称为二次索引( secondary index )。 正常情况下,索引包含了所指向的行的物理地址,即 rowid 。而 IOT 二次索引无法做到这一点;它必须使用另外某种方法来指示行的地址。这是因为 IOT 中 的行可以大量移动, 而且它不像堆组织表中的行那样 “ 迁移 ” 。 IOT 中的行肯定在索引结构中的每个位置上,这取决于它的主键值;只有当索引本身的大小和形状 发生改变时行才会移动(下一章将更详细地讨论索引结构如何维护)。

    为了适应这种情况, O racle 引入了一个逻辑 rowid ( logical rowid )。 这些逻辑 rowid 根据 IOT 主键建立。对于行的当前位置还可以包含一个 “ 猜测 ” ,不过这个猜测几乎是错的,因为稍过一段时间后, IOT中的数据可能就会 移动。这个猜测是行第一次置于二次索引结构中时在 IOT 中的物理地址。如果 IOT 中 的行必须移动到另外一个块上,二次索引中的猜测就会变得 “ 过时 ” 。因 此,与常规表相比, IOT 上的索 引效率稍低。在一个常规表上,索引访问通常需要完成一个 I/O 来扫描索引结构,然后需要一个读来读取表数据。对于 IOT , 通常要 完成两个扫描;一次扫描二次结构,另一次扫描 IOT 本身。除此之外, IOT 上的索引可以使用非主键列提供 IOT 数据的快速、高效访问。

索引组织表小结

    在 建立 IOT 时,最关键的是适当地分配数据,即哪些数据存储在索引块上,哪些数据存储在溢出段上。对溢出条件不同的各种场景进行基准测试,查看对 INSERT 、 UPDATE 、 DELETE 和 SELECT 分别有怎样的影响。如果结构只建立一次,而且要频繁读取,就应该尽可能地把数据放在索引块上(最合适获取),要么频繁地组织索引中的数据(不适于修改)。堆表的 freelist 相关考虑对 IOT 也同样适用。 PCTFREE 和PCTUSED 在 IOT 中 是两个重要的角色。不过, PCTFREE 对于 IOT 不像对于堆表那么重要,另外 PC TUSED 一般不起作用。不过,考虑 OVERFLOW 段时, PCTFREE 和 PCTUSED 对于 IOT 的意义将与对于堆表一样重大;要采用与堆表相同的逻辑为溢出段设置这两个参数。

(文/Buddy)

本文来源:http://www.cnblogs.com/nieliu/archive/2012/05/04/2482223.html


如果给你带来帮助,欢迎微信或支付宝扫一扫,赞一下。