下面我们讨论一下由于数据存储为索引而带来的Rowid、问题。

6、Logical Rowid & Secondary

Index

在的环境下,我们是不能保证一个固定的物理Rowid的。

堆表()中,一行数据被保存在一个物理位置(file no. + block

no.)之后,在正常保存行为中,即使发生行迁移现象,它的rowid是不会发生变化的。只有在进行数据表存储重构,如move和shrink

space的时候才会发生新的rowid赋予。

堆表rowid的固定给我们带来一个好处,就是连带的数据表索引叶子节点上面的的rowid永远有效的,除非发生move或者和shrink

space操作(此时索引失效)。

但是,IOT存在一些问题。索引叶子节点的分裂操作是相当频繁的,我们很难保证一个数据行维持在一个rowid不会发生大的变化。当然,如果我们保证每次访问数据表都是通过主键primary

key方式,变化的rowid不会有任何影响。问题出在非主键的索引,IOT中称之为“二级索引”Secondary

Index上。

对于一般的二级索引,如果叶子节点上保留数据行的rowid,那么失效的rowid意味着所有对应的二级索引非常容易变为invalid状态。

在很多数据库版本,包括早期的版本中,对于Secondary

Index是不支持的。最近的oracle中,引入了Logical

Rowid和Physical

Guess的方法,才最终解决了Secondary

Index问题。

SQL> select rowid,

object_id from t_iot where rownum<5;

ROWIDOBJECT_ID

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

-----------

*BABBVmoCwQP+2

*BABBVmoCwQT+3

*BABBVmoCwQX+4

*BABBVmoCwQb+5

对IOT而言,rowid基本上是不合乎我们常见的heap table

rowid格式的。我们可以对t_iot添加secondary

index。

SQL> create index

idx_t_iot_name on t_iot(object_name);

Index

created

SQL> exec

dbms_stats.gather_table_stats(user,'T_IOT',cascade =>

true);

PL/SQL procedure successfully

completed

从数据字典中看,索引idx_t_iot_name没有什么额外的差异,只是对于一般索引来说,取值略高。

SQL> select index_Name,

index_type, clustering_factorfrom dba_indexes where

wner='SYS' and index_name='IDX_T_IOT_NAME';

INDEX_NAMEINDEX_TYPECLUSTERING_FACTOR

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

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

IDX_T_IOT_NAMENORMAL55006

SQL> select count(*) from

t_iot;

COUNT(*)

----------

72604

SQL> select

sum(bytes)/1024/1024, count(*) from dba_extents where wner='SYS'

and segment_name='IDX_T_IOT_NAME';

SUM(BYTES)/1024/1024COUNT(*)

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

----------

419

对于一个7万余条记录的数据表索引,占到了19个分区,总看空间4M。那么,如果是一般的heap table

index呢?空间如何?

SQL> desc

t_heap;

NameTypeNullable

Default Comments

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

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

OBJECT_IDNUMBER(10)

OBJECT_NAME VARCHAR2(100)

Y

SQL> create index

idx_t_heap_name on t_heap(object_name);

Index

created

SQL> select count(*) from

t_heap;

COUNT(*)

----------

72605

SQL> select

sum(bytes)/1024/1024, count(*) from dba_extents where wner='SYS'

and segment_name='IDX_T_HEAP_NAME';

SUM(BYTES)/1024/1024COUNT(*)

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

----------

318

相同取值,正常index只有3M空间,约占到18个分区。说明:Secondary

Index对比一些其他索引,有很多特殊的信息在其中。

SQL> col object_name for

a20;

SQL> select object_id,

object_name from dba_objects where object_name in

('IDX_T_HEAP_NAME','IDX_T_IOT_NAME');

OBJECT_ID

OBJECT_NAME

----------

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

75146

IDX_T_HEAP_NAME

75143

IDX_T_IOT_NAME

我们尝试将两个索引树dump出来,探索其结构差异。

SQL> select value from

v$diag_info where name='Default Trace File';

VALUE

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

/u01/diag/rdbms/wilson/wilson/trace/wilson_ora_9101.trc

--堆表索引结构

SQL> alter system set

events 'immediate trace name treedump level75146';

System

altered

--IOT表索引结构

SQL> alter system set

events 'immediate trace name treedump level75143';

System

altered

首先,我们分析一下一般堆表的索引情况。由于篇幅原因,只截取部分内容。

*** ACTION NAME:(Command

Window - New) 2012-10-05 02:43:39.561

----- begin tree

dump

branch:0x415c01 4283393(0: nrow: 2, level:

2)

branch:0x415d3b

4283707(-1: nrow: 312, level: 1)

leaf:0x415c02

4283394(-1: nrow: 184 rrow: 184)

leaf:

0x415c03 4283395 (0: nrow: 184 rrow: 184)

leaf:

0x415c04 4283396 (1: nrow: 188 rrow: 188)

leaf:

0x415c05 4283397 (2: nrow: 190 rrow: 190)

leaf:

0x415c06 4283398 (3: nrow: 184 rrow: 184)

leaf:

0x415c07 4283399 (4: nrow: 186 rrow: 186)

leaf:

0x415c08 4283400 (5: nrow: 185 rrow: 185)

从Dump结果上,我们可以清晰看到IDX_T_HEAP_NAME是一个两层索引结构。根节点地址为0x415c01(file=1,

block=89089)。

SQL> select

to_number('415c01','xxxxxx') from dual;

TO_NUMBER('415C01','XXXXXX')

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

4283393

其中的一个数据块0x415c06进行试验,转化为十进制地址为4283398,二进制地址为:10000010101110000000110。根据rfile解析规则,最终地址为:file_no=1,block_no=89094。

SQL> alter system dump

datafile 1 block 89094;

System

altered

Dump文件中叶子节点的内容为:

row#0[8000] flag: ------,

lock: 0, len=32

col 0; len 22;

(22):

2f 31 34 64 63 62 36

32 32 5f 53 79 6e 74 68 4c 61 62 65 6c 55 49

col 1; len 6;

(6):00 41

55 91 00 4b

row#1[7968] flag: ------,

lock: 0, len=32

col 0; len 22;

(22):

2f 31 34 64 63 62 36

32 32 5f 53 79 6e 74 68 4c 61 62 65 6c 55 49

col 1; len 6;

(6):00 41

55 91 00 4c

row#2[7928] flag: ------,

lock: 0, len=40

col 0; len 30;

(30):

2f 31 34 65 33 63 31

31 32 5f 50 4e 47 45 6e 63 6f 64 65 50 61 72 61 6d

50

61 6c 65 74

74

col 1; len 6;

(6):00 41

5b 9a 00 9d

从结构上猜测,col0和col1分别表示索引列取值和对应rowid信息。而IOT的secondary

index如何呢?

*** 2012-10-05

02:43:55.944

----- begin tree

dump

branch: 0x4154b9 4281529 (0:

nrow: 2, level: 2)

branch:

0x415acd 4283085 (-1: nrow: 330, level: 1)

leaf:

0x4154ba 4281530 (-1: nrow: 160 rrow: 160)

leaf:

0x4154bb 4281531 (0: nrow: 158 rrow: 158)

leaf:

0x4154bc 4281532 (1: nrow: 163 rrow: 163)

leaf:

0x4154bd 4281533 (2: nrow: 162 rrow: 162)

leaf:

0x4154be 4281534 (3: nrow: 163 rrow: 163)

leaf:

0x4154bf 4281535 (4: nrow: 160 rrow: 160)

leaf:

0x4154c0 4281536 (5: nrow: 159 rrow: 159)

leaf:

0x4154c1 4281537 (6: nrow: 161 rrow: 161)

leaf:

0x4154c2 4281538 (7: nrow: 160 rrow: 160)

叶子节点0x4154bc,对应具体的二进制为:10000010101010010111100。分析获得的位置为:file_no=1,block_no=87228。

我们将该块dump出。

SQL> alter system dump

datafile 1 block 87228;

System

altered

row#0[7986] flag: K-----,

lock: 0, len=46

col 0; len 30;

(30):

2f 31 32 30 66 34 37

30 38 5f 46 75 6c 6c 48 54 4d 4c 44 6f 63 75 6d 65

6e

74 61 74 69

6f

col 1; len 4;

(4):c3 04

39 24

tl: 8 fb: --H-FL--

lb: 0x0cc:

1

col0: [ 4]00 41 59

3e

row#1[7940] flag: K-----,

lock: 0, len=46

col 0; len 30;

(30):

2f 31 32 30 66 64 37

36 64 5f 4f 72 61 63 6c 65 44 61 74 61 62 61 73 65

4d

65 74 61 44

61

col 1; len 4;

(4):c3 02

50 1a

tl: 8 fb: --H-FL--

lb: 0x0cc:

1

col0: [ 4]00 41 54

a1

row#2[7894] flag: K-----,

lock: 0, len=46

col 0; len 30;

(30):

2f 31 32 30 66 64 37

36 64 5f 4f 72 61 63 6c 65 44 61 74 61 62 61 73 65

4d

65 74 61 44

61

col 1; len 4;

(4):c3 04

4c 1a

tl: 8 fb: --H-FL--

lb: 0x0cc:

1

col0: [ 4]00 41 54

a2

上面标红的部分是我们看到了和Heap Index的差异,正式由于这部分信息的差异,才让IOT Secondary

Index体积略大。

从概念上,Secondary Index包括三部分叶子节点内容:索引键值、logical

rowid和对应数据行的主键值。在进行检索的时候,Oracle首先用logical

rowid进行初步的试探,看看对应的位置是否可以找到对应数据。这个过程我们称为physical

guess。

如果找到了对应数据行,那么皆大欢喜。如果没有,oracle就只能通过数据行的主键值,进行IOT索引树定位。这个过程,要重复多读一个段结构。

具体Secondary Index的分析,留待下次进行更加详细的说明。

7、IOT的使用

我们已经在一个系列中,详细介绍了IOT的特性,最后我们聊一聊IOT应用的场景。总的来说,笔者认为IOT在一般系统的应用中,是没有很广泛的发挥场景的。在没有明确的分析和POC实验基础上,我们不要轻易进行IOT决策。具体来说,有如下的几点:

üIOT环境下,有更多的限制

我们常使用的堆表,虽然有各种问题,但是是目前我们可以得到的适应性最广,优化策略最多的一种表存储结构。IOT则要受到很多的限制,例如:IOT必须要制定主键,也就是定义出核心访问方式;PCTThreshold参数如果设置了,但是没有指定overflew

segment,那么超出阈值的数据行是不会被接受,要抛出异常。IOT表中分区和Lob类型不能同时使用。IOT维护工作要更多。

ü单一读取,读多写少的操作类型

我们定义出IOT后,实际上就是规定了数据表的核心访问方式。当我们使用主键条件时,IOT可以方便的帮助我们定位记录。但是其他查询条件应用secondary

index的效率就是一个问题。而且secondary

index也是不久前才支持的Oracle特性。如果我们的数据表应用是一个多种检索方式并存的操作表,那么IOT不是理想的选择。

索引操作本身对增加、修改和删除等DML操作是具有性能影响的。在IOT环境下,这种影响只会让其更加剧烈。所以,如果数据表不是很少修改的数据表,那么使用IOT不是最好的选择。

ü主键列和列数目的约束

索引叶子节点中就能将所有数据行列保存在叶子节点上。而索引叶子节点是变化分裂频繁的对象。所以,如果数据行列数很多,或者数据主键列相对很小,那么IOT的效果是不好的。

8、结论

Heap,IOT和Cluster是数据表的三大基本存储类型。我们在实际中,要把握原则是:以堆表为核心,默认都使用Heap

Table。如果在架构分析、性能测试和试运行阶段,发现性能问题,可以考虑使用IOT或者Cluster。但是,在选型的时候,一定要明确两种表结构的优缺点和适用范围。

jinyuan oracle,简述Oracle IOT(Index Organized Table)(下)相关推荐

  1. IOT(Index Organized Table)

    我们知道一般的表都以堆(heap)的形式来组织的,这是无序的组织方式.Oracle还提供了一种有序的表,它就是索引组织表,简称IOT表.IOT表上必须要有主键,而IOT表本身不对应segment,表里 ...

  2. 索引组织表(index organized table, IOT)

    1.索引组织表 索引组织表(index organized table, IOT)就是存储在一个索引结构中的表.存储在堆中的表是无组织的(也就是说,只要有可用的空间,数据可以放在任何地方),IOT中的 ...

  3. oracle索引组织表(Index Organizied Table)

    索引组织表(index organized table, IOT)就是存储在一个索引结构中的表.存储在堆中的表是无组织的(也就是说,只要有可用的空间,数据可以放在任何地方),IOT中的数据则按主键存储 ...

  4. oracle rebuild online,alter index rebuild

    Oracle alter index rebuild 说明[日期:2011-06-12]来源:Linux社区 作者:tianlesoftware[字体:大中小] 一.官网说明 在MOS 上的一篇文章讲 ...

  5. oracle full table scan,ORACLE优化之执行规划(1) - TABLE FULL SCAN/INDEX FULL SCAN

    ORACLE优化之执行规划(1) - TABLE FULL SCAN/INDEX FULL SCAN TABLE FULL SCAN 全表扫描,表示表中所有记录都被访问到.如果表很大, 该操作对查询性 ...

  6. oracle12178错误,Oracle学习笔记_20080522:Index FS vs Index FFS

    Index Full Scan vs Index Fast Full Scan index full scan和index fast full scan是指同样的东西吗?答案是no.两者虽然从字面上看 ...

  7. ORACLE虚拟索引(Virtual Index)

    ORACLE虚拟索引(Virtual Index)   虚拟索引概念 虚拟索引(Virtual Indexes)是一个定义在数据字典中的假索引(fake index),它没有相关的索引段.虚拟索引的目 ...

  8. oracle imp导入时出现skipping table

    最近有同事在使用传统的imp工具导入数据时,总是提示收到skipping table的提示,也就是表被跳过,而不是被重建.即使是将目标数据库上的表对象删除,仍然无法导入.因此记录一下,供大家参考. 1 ...

  9. 简述oracle数据库特殊状态,【OracleDB】 01 概述和基本操作

    实例概念: Oracle有一个特殊的概念 Oracle数据库 = 数据库 + Oracle文件系统 + Oracle实例 实例处理Oracle的请求,调用文件系统 然后返回结果响应给客户端 单实例和多 ...

最新文章

  1. Michael Jordan:当下的AI其实都是伪“AI”
  2. 改进博客园Markdown显示功能(加代码行号、显示代码所用编程语言)
  3. swagger 修改dto注解_Swagger 详解
  4. 美团多渠道打包原理以及使用
  5. 文都计算机统考讲义,考研计算机文都基础班讲义.doc
  6. 积分兑换平台(这是一种剥削么?强烈求拍砖)
  7. Android service Binder用法
  8. Nginx教程1:基本概念
  9. docker中启动Springboot时异常之Failed to instantiate [com.zaxxer.hikari.HikariDataSource]
  10. linux安装安卓fastboot,Android的fastboot协议
  11. (研究向)如何使用Windows任务管理器看BadApple
  12. 统计学中p值计算公式_统计学中的P值应该怎么计算
  13. 矩阵的LU分解——MATLAB实现
  14. SQL分组统计-每个学科前三名
  15. 通过网页端保存ins图片的方法(谷歌浏览器)
  16. 一个非常有意思的网站
  17. 字符串库函数(1)Strlen,strcpy,strcat,strcmp
  18. golang学习资源
  19. 深度学习基础篇【5】从0开始搭建YOLOV5 并进行测试
  20. python自动投递_利用python如何在前程无忧高效投递简历

热门文章

  1. jquery 处理json字符串
  2. 简单手绘背景绘画过程-------树!
  3. Linux 命令(128)—— useradd 命令
  4. [Lisp]slime
  5. 《校园封神榜》个人工作总结——第十天
  6. python动态创建字典_如何在Python中创建动态命名字典?
  7. P1280 尼克的任务
  8. 算法总结之递推与递归
  9. Linux下添加服务
  10. 物联网市场潜力巨大,中国移动加强布局