简述Oracle IOT(Index Organized Table)
转:http://blog.itpub.net/17203031/viewspace-744477
对关系型数据库产品(RDBMS)而言,一个重要特性就是:数据信息都被组织为二维数据表,信息的表达可以通过一系列的关联(Join)来完成。具体数据库产品在实现这个标准的时候,又有千差万别的特点。就是一个特定的数据库RDBMS产品,往往也提供不同的实现方法。
1、从堆表(Heap Table)到索引组织表(Index Organization Table)
Oracle作为一款成熟的数据库软件产品,就提供了多种数据表存储结构。我们最常见的就是三种,分别为堆表(Heap Table)、索引组织表(Index Organization Table,简称为IOT)和聚簇表(Cluster Table)。
Heap Table是我们在Oracle中最常使用的数据表,也是Oracle的默认数据表存储结构。在Heap Table中,数据行是按照“随机存取”的方式进行管理。从段头块之后,一直到高水位线一下的空间,Oracle都是按照随机的方式进行“粗放式”管理。当一条数据需要插入到数据表中时,默认情况下,Oracle会在高水位线以下寻找有没有空闲的地方,能够容纳这个新数据行。如果可以找到这样的地方,Oracle就将这行数据放在空位上。注意,这个空位选择完全依“能放下”的原则,这个空位可能是被删除数据行的覆盖位。
如果Heap Table段的HWM下没有找到合适的位置,Oracle堆表才去向上推高水位线。在数据行存储上,Heap Table的数据行是完全没有次序之分的。我们称之为“随机存取”特征。
对Heap Table,索引独立段的添加一般可以有效的缓解由于随机存取带来的检索压力。Index叶子节点上记录的数据行键值和Rowid取值,可以让Server Process直接定位到数据行的块位置。
聚簇(Cluster Table)是一种合并段存储的情况。Oracle认为,如果一些数据表更新频率不高,但是经常和另外一个数据表进行连接查询(Join)显示,就可以将其组织在一个存储结构中,这样可以最大限度的提升性能效率。对聚簇表而言,多个数据表按照连接键的顺序保存在一起。
通常系统环境下,我们使用Cluster Table的情况不太多。Oracle中的数据字典大量的使用聚簇。相比是各种关联的基表之间固定连接检索的场景较多,从而确定的方案。
最后就是本系列的IOT(Index Organization Table)。同Cluster Table一样,IOT是在Oracle数据表策略的一种“非主流”,应用的场景比较窄。但是一些情况下使用它,往往可以起到非常好的效果。
简单的说,IOT区别于堆表的最大特点,就在于数据行的组织并不是随机的,而是依据数据表主键,按照索引树进行保存。从段segment结构上看,IOT索引段就包括了所有数据行列,不存在单独的数据表段。
IOT在保存结构上有一些特殊之处,应用在一些特殊的场景之下。本系列将逐个分析IOT的一些特征,最后讨论我们究竟在什么样的场景下,可以选择IOT作为数据表方案。
2、IOT基础
在创建使用IOT上,我们要强调Primary Key的作用。对一般的堆表而言,Primary Key是可有可无的。一种说法是:当一个堆表没有设置主键的时候,rowid伪列就是对应的主键值。而且,Primary Key可以在数据表创建之后进行追加设置。
但是,IOT对于主键的设置格外严格,要求创建表的时候就必须指定明确的主键列。下面我们通过一系列的实验来证明,实验环境为Oracle 11g。
SQL> select * from v$version;
BANNER
------------------------------------
Oracle Database 11g Enterprise Edition Release 11.2.0.1.0 - Production
PL/SQL Release 11.2.0.1.0 - Production
CORE 11.2.0.1.0 Production
我们使用相同的结构,来创建出IOT和Heap Table对照。
--不指定主键,是无法创建IOT;
SQL> create table m (id number) organization index;
create table m (id number) organization index
ORA-25175: 未找到任何 PRIMARY KEY 约束条件
在create table语句后面使用organization index,就指定数据表创建结构是IOT。但是在不指定主键Primary Key的情况下,是不允许建表的。
SQL> create table t_iot (object_id number(10) primary key, object_name varchar2(100)) organization index;
Table created
SQL> create table t_heap (object_id number(10) primary key, object_name varchar2(100));
Table created
(插入相同数据来源行……)
SQL> exec dbms_stats.gather_table_stats(user,'T_IOT',cascade => true);
PL/SQL procedure successfully completed
SQL> exec dbms_stats.gather_table_stats(user,'T_HEAP',cascade => true);
PL/SQL procedure successfully completed
从数据字典的层面上,我们分析一下两个数据表的差异,一窥IOT的特点。
SQL> select table_name, tablespace_name, blocks, num_rows from user_tables where table_name in ('T_IOT','T_HEAP');
TABLE_NAME TABLESPACE_NAME BLOCKS NUM_ROWS
------------------------------ ------------------------ ---------- ----------
T_HEAP SYSTEM 157 72638
T_IOT 72638
SQL> select segment_name, blocks, extents from user_segments where segment_name in ('T_IOT','T_HEAP');
SEGMENT_NAME BLOCKS EXTENTS
-------------------- ---------- ----------
T_HEAP 256 17
上面两句SQL揭示了几个问题。首先,Oracle承认IOT是一个数据表,并且统计了数据行数。但是对数据表的存储表空间和大小没有明确的说明,user_tables视图中这部分的内容为空。
其次,从段结构来看,Oracle明确不承认存在T_IOT段。因为如果有段segment对象,就意味有空间分配。但是数据表有数据,是存放在哪里呢?
我们知道,给数据表添加索引的时候,Oracle会自动的添加一个唯一索引。那么我们去检查一下这部分的结构情况。
SQL> select index_name, index_type, table_name, PCT_THRESHOLD, CLUSTERING_FACTOR from user_indexes where table_name in ('T_IOT','T_HEAP');
INDEX_NAME INDEX_TYPE TABLE_NAME PCT_THRESHOLD CLUSTERING_FACTOR
-------------------- -------- ---------- ------------- -----------------
SYS_C0012408 NORMAL T_HEAP 256
SYS_IOT_TOP_75124 IOT - TOP T_IOT 50 0
SQL> select segment_name, blocks, extents from user_segments where segment_name in ('SYS_C0012408','SYS_IOT_TOP_75124');
SEGMENT_NAME BLOCKS EXTENTS
-------------------- ---------- ----------
SYS_C0012408 256 17
SYS_IOT_TOP_75124 256 17
索引段是存在的,而且明确标注索引类型为IOT索引。这说明几个问题:
首先,对于IOT而言,只有索引段,没有数据段。一般的索引而言,叶子节点上只有索引列的取值和rowid。而对于IOT而言,主键索引上对应就是数据行和索引列取值。
其次,IOT的溢出段阈值(PCT_THRESHOLD)。这是Oracle IOT的特殊策略。简单的说,当我们把全部数据行保存在叶子节点上,一旦发生主键值的变化、新值插入、删除等动作,索引叶子块的分裂动作是频繁的。数据行保存在叶子节点上只会让这样的分裂动作更加频繁和后果严重。Oracle提出将一部分的非主键列单独存储,这个参数就是比例值。
最后,我们探讨一下IOT索引的Clustering Factor。Clustering Factor是反映索引叶子节点顺序和数据保存行直接离散程度的综合性指标。一般来说,堆表的Clustering Factor是随着DML操作不断退化的过程。Clustering Factor是影响到Oracle索引路径成本的一个重要参数(http://space.itpub.net/17203031/viewspace-680936),会影响到CBO的成本决策。 IOT的索引这部分的值永远为0,因为索引的顺序就是数据行的顺序,两者存储顺序相同,绝对一致。
3、IOT与执行计划
在IOT数据表下,我们通常的执行计划会如何呢?普通Heap Table和IOT在这部分的差异很大。
通常而言,Heap Table的索引路径伴随着两次段结构的读取——索引段和数据段。先读取索引段段头,经历根节点、分支节点、叶子节点,最后获取到结果集合rowid列表。之后进行回表操作,使用rowid依次查询数据表的行。
但是IOT表可以不同。索引和数据保留在一起,理论上拿到了叶子节点,也就是拿到了数据行。IOT是不存在回表操作的,所以相对heap table来说,回表部分成本是节省的。
下面我们通过执行计划,来看IOT的特征。
SQL> explain plan for select * from t_iot where object_id=1000;
Explained
SQL> select * from table(dbms_xplan.display);
PLAN_TABLE_OUTPUT
---------------------------------------------------------------------------
Plan hash value: 2277898128
--------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Tim
---------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1 | 11 | 1 (0)| 00:
|* 1 | INDEX UNIQUE SCAN| SYS_IOT_TOP_75124 | 1 | 11 | 1 (0)| 00:
-------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
1 - access("OBJECT_ID"=1000)
13 rows selected
SQL> explain plan for select * from t_iot;
Explained
SQL> select * from table(dbms_xplan.display);
PLAN_TABLE_OUTPUT
-------------------------------------------------------------------------------
Plan hash value: 4201110863
-------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)|
-------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 72638 | 780K| 47 (0)|
| 1 | INDEX FAST FULL SCAN| SYS_IOT_TOP_75124 | 72638 | 780K| 47 (0)|
------------------------------------------------------------------------
8 rows selected
对于IOT,我们要保证访问的数据表的方式是主键路径为主。在上面的两个执行计划中,我们按照主键进行检索,路径为Index Unique Scan。全表扫描为Index Fast Full Scan。两者都没有明显的回表动作。
试想,如果数据表较小,Index Full Scan也是IOT表常常出现的执行路径。
对一般的Heap Table,执行路径如何呢?
SQL> explain plan for select * from t_heap where object_id=1000;
Explained
SQL> select * from table(dbms_xplan.display);
PLAN_TABLE_OUTPUT
----------------------------------------------------------------------------
Plan hash value: 1833345710
-----------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)
---------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1 | 11 | 2 (0)
| 1 | TABLE ACCESS BY INDEX ROWID| T_HEAP | 1 | 11 | 2 (0)
|* 2 | INDEX UNIQUE SCAN | SYS_C0012408 | 1 | | 1 (0)
--------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
2 - access("OBJECT_ID"=1000)
14 rows selected
SQL> explain plan for select * from t_heap;
Explained
SQL> select * from table(dbms_xplan.display);
PLAN_TABLE_OUTPUT
---------------------------------------------------------------------------
Plan hash value: 1253663840
---------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
----------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 72638 | 780K| 42 (0)| 00:00:01 |
| 1 | TABLE ACCESS FULL| T_HEAP | 72638 | 780K| 42 (0)| 00:00:01 |
----------------------------------------------------------------------------
8 rows selected
普通堆表都不能避免出现回表动作。
最后,我们要声明一下回表动作的成本影响。IOT和Heap Table一个很大的执行计划差异,就是回表。但是从成本上计算,CBO并不是因为回表动作才确定执行计划,而是Clustering Factor的影响。
对堆表而言,Clustering Factor都是一个很大的问题,无论是CBO的成本公式上,还是不断Degrade的前景。IOT一个突出优势就是直接消灭了Clustering Factor的成本因素。
但是这也就带来一个问题,一个数据表只能按照主键的顺序进行组织,辅助索引(Secondary Index)的问题是很多版本Oracle和IOT使用者争议的话题。Secondary Index问题我们在后面会继续讨论到。
下篇中我们会继续讨论有关IOT维护等其他内容。
简述Oracle IOT(Index Organized Table)的更多相关文章
- IOT(Index Organized Table)
我们知道一般的表都以堆(heap)的形式来组织的,这是无序的组织方式.Oracle还提供了一种有序的表,它就是索引组织表,简称IOT表.IOT表上必须要有主键,而IOT表本身不对应segment,表里 ...
- Oracle composite index column ordering
Question: I have a SQL with multiple columns in my where clause. I know that Oracle can only choos ...
- Oracle临时表(Temporary Table)
GLOBAL TEMPORARY代表全局临时表临时表的元数据存储在数据字典里面 只当第一条DML命令发生的时候才为这张表的段分配空间 临时表数据的可见范围应该是会话级别或是事务级别的 会话或者事务级别 ...
- Oracle基础 10 表 table
--查看表的结构 desc ygb; select * from user_tab_columnswhere table_name='YGB'; --新建表ygb create table ygb( ...
- Oracle alter index rebuild 与 ORA-08104 说明
在ITPUB 论坛上看到的一个帖子,很不错.根据论坛的帖子重做整理了一下. 原文链接如下: alter index rebuild online引发的血案 http://www.itpub.net/t ...
- oracle alter index rebuild offline与online
oracle index build online与offline测试环境为oracle 11.2.0.4 --sql test SQL> conn test/test )); begin .. ...
- Oracle临时表GLOBAL TEMPORARY TABLE
临时表:像普通表一样,有结构,但是对数据的管理上不一样,临时表存储事务或会话的中间结果集,临时表中保存的数据只对当前 会话可见,所有会话都看不到其他会话的数据,即使其他会话提交了,也看不到.临时表不存 ...
- Oracle 11G INDEX FULL SCAN 和 INDEX FAST FULL SCAN 对比分析
SQL> drop table test; 表已删除. SQL> create table test as select * from dba_objects where 1!=1; 表已 ...
- ORACLE中index的rebuild(转)
Oracle里大量删除记录后,表和索引里占用的数据块空间并没有释放. table move可以释放已删除记录表占用的数据块空间,整理碎片.如果将表格用move方式整理碎片后,索引将失效,这时需要将索引 ...
随机推荐
- maven项目(转)
我记得在搞懂maven之前看了几次重复的maven的教学视频.不知道是自己悟性太低还是怎么滴,就是搞不清楚,现在弄清楚了,基本上入门了.写该篇博文,就是为了帮助那些和我一样对于maven迷迷糊糊的人. ...
- BOOST_PREVENT_MACRO_SUBSTITUTION
[BOOST_PREVENT_MACRO_SUBSTITUTION] 用于防止函数被macro替换的问题. 例如: 参考: 1.https://blog.csdn.net/yanxiangtianji ...
- Servlet第五篇(会话技术之Session)
Session 什么是Session Session 是另一种记录浏览器状态的机制.不同的是Cookie保存在浏览器中,Session保存在服务器中.用户使用浏览器访问服务器的时候,服务器把用户的信息 ...
- 连接HTTP服务器
一.前提 Android 系统上面默认所有Http的请求都被阻止了. 需要在androidmanifest.xml的 application标签上加入 android:usesCleartextTra ...
- 19-06 【phpunit和docker】
phpunit简介 在用PHP做项目的时候,有时候我们需要写一些测试代码,其中可能包含单元测试(比如字符串处理,ip解析,mobile解析等). 我们常用的工具是phpunit,它很方便地帮我们组织测 ...
- 使用python画一只佩奇
打开界面: 打开python shell界面. 建立脚本: 单击"file"——"new file"来建立脚本. 编写代码: 具体的代码如下. import t ...
- 炫酷MD风之dialog各种对话框
这个demo也是我从别人那里学来的,不是本人写的代码,我也是个MD初学者.把这个demo分享给看到的你,希望对你有帮助. 直接上图: demo地址:百度网盘:链接:https://pan.baidu. ...
- CAPTCHA--验证码
验证码开发有两种方法: 1.自己用代码画一个 2.调用ValidateCode.jar工具包 第一种方式: 创建一个动态web工程 编写一个Servlet,在该Servlet内进行如下操作 验证码开发 ...
- 7C - 折线分割平面
我们看到过很多直线分割平面的题目,今天的这个题目稍微有些变化,我们要求的是n条折线分割平面的最大数目.比如,一条折线可以将平面分成两部分,两条折线最多可以将平面分成7部分,具体如下所示. Input ...
- 记一次mac下使用mamp集成环境配置lumen项目自定义域名遇到的花样问题
1.安装好mamp集成环境,自行百度. 2.从公司项目版本库里将项目克隆到本地. 好了,开始配置自定义域名来访问项目,以下是遇到的问题集锦... 1.web服务器使用的nginx,配置完域名访问报40 ...