索引表简介

2023-11-16

索引表简介

1、索引的内部构造

因为在索引表中涉及到索引的内部构造知识,所以下面会进行简单的介绍。

首先,如果没有索引,当你想要去查找某个值的时候,你不得不对数据进行顺序扫描,如果一张表有n行,那么使用顺序扫描的平均扫描行数为n/2,一旦表的行数越来越多,这种顺序扫描的效率将大幅下降;如果有索引的参与,使用平衡树扫描的平均扫描行数为log(n),表的行数越多,这种结构带来的扫描效率并不会下降多少。所以Oracle在内部存储索引数据时,使用一种被称为平衡树的结构(B-tree)。如下图所示:

它由两部分组成:

A.      Branch blocks(树枝块):处于最顶层的树枝块又称为根树枝块(root branch blocks);这部分内容在索引一文中再做深入讨论。

B.      LeafBlocks(叶块):处于最底层的块被称为叶块(注意:之所以称为平衡树,是指:平衡树的所有叶块与根树枝块的深度都是一样的);上图是在某表的单列上建立索引;当你建立此索引时,Oracle会自动抓取此列的列值(键值)进行排序;如果是在多列上建立索引呢?Oracle对其排序是按照此列组(属性组)的键值进行排序;因为上图只有一列,那么键值就是其列值。那么,Oracle会把经过排序的列表的值分成(纵向划分)一个一个的区(一个区表示一定宽度的块的范围),这些区以双向链表的结构来组织(所谓双向链表就是一个区带有两个指针,一个指上,一个指下,如上图所示)。你可能会有疑问:那么一个叶块是不是就对应一个数据块呢?答案是否定的!一个叶块不一定就对应一个数据块,有可能一个数据块中有多个叶块,并且这些叶块在物理上不一定就邻接;也有可能某个索引的叶块在这个数据块中,而另一个叶块又在另一个数据块中。如果叶块中的数据是字符数据,那么Oracle还会自动把它们转换为对应的二进制数据(根据所指定的此数据库的字符集设置),所以上图中的叶块数据的格式还不是真正存储在数据库中的数据格式。

2、索引表

索引表使用一种平衡树(B-tree)变体(相对于上节的平衡树)来组织数据的存储(存储结构);而常规的表使用的是(也是一种数据结构)来组织数据的存储(这种数据结构是一种无序的集合)。在这里,所谓平衡树变体结构是指存储在其中的数据需要排序,并且数据的排序是按照主键排序的方式;索引表不仅像索引一样存储主键值(这里的索引指的是在表中的所有列上建立索引),而且在B-tree中的每个索引条目(上节所说的一个叶块)还存有非键值。

图5-9 一个正规表和一个索引表的比较

表5-3索引表和常规表不同的地方

Ordinary Table

Index-Organized Table

Rowid唯一标识一行。主键可指定也可不指定(因为你已经有rowid了)。

由主键来唯一标识一行。主键肯定就必须指定。

使用物理rowid,允许使用它创建二级索引。

使用逻辑rowid,允许使用它创建二级索引。

访问基于物理rowid(使用物理地址)。

访问基于逻辑rowid(使用主键,有可能使用物理猜想)。

返回所有行,使用顺序扫描。

返回所有行,使用全索引扫描。

能被存储在一个簇中。

不能被存储在一个簇中。

一列中能够含有数据类型为LONG、LOB的数据。

能含有LOB数据类型,但不能有LONG数据类型

 

小结:

如果有一张常规表,在它的所有列上创建一个索引,那么这张表和在这张表上的索引的组合就有点类似于索引表;不过,这个索引并不一定就拥有这张表所有的键值,因为这时索引的规范是:在同一个数据块中的键值只要能够被区分,那么就不必要整个键值都做存储,而只要存储键值的一部分;而索引表是存储了表中的所有键值;不过,索引表的想法就是由此开始的(因为它能提供最快速的访问)。

常规表和其索引是两个独立的存储结构,而索引表是一个单一的存储结构;

索引表的平衡树(B-tree)存储结构的条目是由<primary_Key_value,

non_primary_key_column_values>值对组成(它是使用逻辑rowids);而常规表索引的平衡树(B-tree)存储结构的条目是由<Key_value,rowid>值对组成(它是使用物理rowids)。

应用程序可以像使用常规表一样使用索引表(使用SQL语句);只不过,对索引表的操作是数据库系统内部通过操作相对应的B-tree数据结构索引来完成的。

2.1溢出(Overflow)

平衡树式的索引条目(入口)通常很小,因为对于常规表的索引来说,它们的条目仅仅包含<键值,rowid>对(在上一节总结中所举的例子是一种极端情况,只是用来理解)。然而对于索引来说,它的入口条目就比较大了,因为它必须包含整一个的行(不管你是键值还是非键值,你都得储存);这样就很有可能摧毁密集簇的平衡树索引。

Oracle提供OVERFLOW字句来处理这个问题。你能指定一个overflow表空间,如果必要,你还能把一行分成以下两个部分(一部分存储在索引中,而另一部分就存储在overflow段中):

·        索引条目包含:主键列中的主键值、一个物理rowid(也就是一个指向行溢出部分的指针)和一部分可选的非键列的值。

·        overflow部分包含:剩余的非键值。

OVERFLOW又有两个字句:PCTTHRESHOLD(阈值百分比)和INCLUDING

使用PCTTHRESHOLD你能提供一个以百分比来表示的阈值(对块的大小进行限制);如果非键列值超过了这个限制值,那么第一个非键列的值和之后的所有非键列的值都将存储在overflow段。

INCLUDING字句是让你指定某列的列名,这个列名是任意的非键列的列名,此列是出现在CREATE TABLE语句的指定列表中的列,它/它们仍然被存储在行溢出段中。不过,其它的非键列(不在INCLUDING字句中的非键列),也要遵从PCTTHRESHOLD的设置。下面是个例子:

CREATE TABLE admin_docindex2(
        token CHAR(20), 
        doc_id NUMBER,
        token_frequency NUMBER,
        token_offsets VARCHAR2(512),
        CONSTRAINT pk_admin_docindex2 PRIMARY KEY (token, doc_id))
    ORGANIZATION INDEX 
    TABLESPACE admin_tbs
    PCTTHRESHOLD 20
    INCLUDING token_frequency
OVERFLOW TABLESPACE admin_tbs2;
 
2.2二级索引(辅助索引)

索引表上的二级索引能够非常有效地访问索引表,这种索引既不是使用主键列也不是使用主键的某个前缀。Oracle构造这种索引使用的是逻辑的行标识符(logicalrowids),这种rowids是基于表的主键(而不是基于行的物理地址)。这种逻辑rowids包括了一个物理猜想(physical guess),它也是一种物理标识符(物理指针),它唯一标识行的块地址,Oracle能使用这些猜想直接对索引表的叶块进行探测,从而避免主键搜索。不过,在rowids一文中也讲过,由于索引表不拥有永久/不变的物理地址,索引这种物理猜想可能会变得陈旧/无效。

对一个常规表来说,通过一个二级索引进行访问会卷入对二级索引的一次扫描以及一个额外的I/O操作(抓取包含有目标行的数据块);对于索引表来说,通过一个二级索引的变体进行访问依赖于如何使用以及精准的物理猜想:

·        如果没有使用物理猜想,那么访问涉及到两个索引扫描:1、一次二级索引扫描2、紧随其后的一次主键索引扫描

·        如果使用有效的(精准的)物理猜想,那么访问涉及到一次二级索引扫描和一个额外的I/O操作(抓取包含有目标行的数据块,直接定位到了包含此行的数据块)

·        如果使用过期的物理猜想,呢么访问涉及到一次二级索引扫描和一个I/O操作,只不过所抓取到的数据块是错误的,紧随其后的是不得不进行一次主键索引扫描。

2.3索引表上的位图(Bitmap)索引

Oracle支持在被分割或未被分割的索引表上使用位图(bitmap)索引,创建位图索引时需要一张映射表。

2.3.1映射表(Mapping Table)

映射(mapping)表是也是一种堆组织结构的表,它存储着索引表的逻辑rowids,更进一步说,每张映射表的一行存储了索引表的一个逻辑rowids(这个rowids唯一标识索引表的一行)。因此,映射表提供了逻辑rowids和其索引表中的行的一一对应关系,并且这种映射表同样拥有物理rowids。

建立在索引表上的一个位图索引和建立在堆组织结构表上的位图索引很类似,不同的是,前者的位图索引使用的rowids是映射表中的rowids,而不是基表的。每个索引表可以拥有一张映射表,而某个索引表的所有位图都将使用一张映射表。

不管是堆表还是索引表,访问一个位图索引都是使用某个搜索键。如果这个搜索键被找到,那么根据位图的入口条目就可以找到一个物理rowid。对于堆表来说,这个物理rowid是被用来访问其基表的;而对于索引表来说,这个物理rowid是用来访问映射表的,而从索引表又可以获得一个逻辑rowid,这个逻辑rowid又是用来访问索引表的。

通过位图索引好像不会存储逻辑rowids,不过从上面可以看出,这种索引本质还是逻辑的。

注意:

行的移动不会造成位图的失效;但是,行的移动会造成映射表中的逻辑rowid中的物理猜想失效,不过索引表仍然能使用主键进行访问。

 

 

 

2.4分割索引表

你能通过在列值上使用RANGEHASHLIST分割一个索引表。这部分内容在分割一文中再做深入讨论。

2.5堆表和索引表中的UROWID类型列上的平衡树索引

数据类型为UROWID的列也可用于存储根据基于主键的逻辑rowid。Oracle支持在堆表或索引表的UROWID列上创建索引;但是只有当一个查询中谓词的条件为“等于”时,Oracle才会使用此索引,“等于”之外的谓词条件及对此列进行排序都不会使用此索引。

2.6索引表的应用

索引表可应用在以下情况:

·        联机事务处理(OLTP)

·        Internet (例如:搜索引擎和门户网络)

·        电子商务 (例如:电子商店和购物目录)

·        数据仓库

·        分析应用

 

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

索引表简介 的相关文章

  • java.library.path 中没有 ocijdbc12

    我正在尝试使用 OCI 驱动程序通过 java 程序连接到 oracle 以下是配置 Windows 7 32 位 JDK 1 7 Oracle 客户端 11g R2 ojdbc7 jar在我的独立应用程序的类路径中 但我收到以下异常 Ex
  • Oracle使用with子句创建表

    我可以从使用形成的查询创建表吗with clause Sure CREATE TABLE t AS WITH some data AS SELECT 1 as some value FROM dual UNION ALL SELECT 2
  • 通过一个表中的列更新另一表中的列

    我有两张桌子 A 和 B 两者都有一个共同的列 name 并通过列 id 相互链接 表A中的 name 列是空的 而表B中有数据 我的任务是用相应的id填充从表B到表A的该列中的所有数据 我正在使用以下查询 UPDATE A SET A n
  • Oracle 12 对 SQL 中的本地集合类型有问题吗?

    长话短说 我建议讨论下面看到的代码 运行时 Oracle 11 编译器引发 PLS 00306 调用 PIPE TABLE 时参数提示的数量或类型错误 PLS 00642 SQL 语句中不允许使用本地集合类型 Oracle 12编译下面的包
  • java.sql.SQLException: ORA-01005: 给定的密码为空;登录被拒绝

    我在尝试连接到数据库时遇到以下异常 java sql SQLException ORA 01005 null password given logon denied at oracle jdbc driver T4CTTIoer proce
  • 在 Oracle 临时表上放置索引安全吗?

    我读过 不应分析临时表 因为它会破坏其他表的统计信息 指数怎么样 如果我在程序运行期间在表上放置索引 使用该表的其他程序会受到该索引的影响吗 索引是否会影响我的进程以及使用该表的所有其他进程 或者它会单独影响我的过程吗 所有的回复都不是权威
  • 从 oracle 中为每个组选择最新行

    我在留言簿中有一张包含用户评论的表格 列有 id user id 标题 评论 时间戳 我需要为每个用户选择最新行 我尝试使用 group by 执行此操作 但没有管理它 因为我无法在按 user id 分组的同一查询中选择任何其他内容 SE
  • SQL*Loader - 如何忽略具有特定字符的某些行

    如果我有一个以下格式的 CSV 文件 fd sdf dsfds dsfd fd asdf dsfds dsfd fd sdf rdsfds dsfd fdd sdf dsfds fdsfd fd sdf dsfds dsfd fd sdf
  • Oracle - 仅当不存在时才创建索引

    有没有什么方法可以在oracle中创建索引 只有当它们不存在时 就像是 CREATE INDEX IF NOT EXISTS ord customer ix ON orders customer id 仅当索引不存在时添加索引 declar
  • SQL:两个没有完整列匹配的表的并集

    我有一个table A其中有一组列A1 A2和一个具有一组列的 table bB1 B2 碰巧的是A2 B1但其余列不匹配 也不应该匹配 我想附加表格 所以我使用UNION ALL 对于不匹配的列 我使用null as COLUMN NAM
  • oracle日期序列?

    我有一个 oracle 数据库 我需要一个包含 2 年所有日期的表 例如来自01 01 2011 to 01 01 2013 首先我想到了一个序列 但显然唯一支持的类型是数字 所以现在我正在寻找一种有效的方法来做到这一点 欢呼骗局 如果您想
  • 如何终止正在运行的 SELECT 语句

    如何通过终止会话来停止正在运行的 SELECT 语句 该命令不断根据 SELECT 语句向我提供输出 我想在其间停止它 As you keep getting pages of results I m assuming you starte
  • 将游标中的数据合并为一个

    我有一个存储过程 它多次执行另一个存储过程 我需要联合并返回数据 这是在执行第二个过程后得到的 我可以以某种方式将多个游标中的数据合并到另一个游标中吗 没有临时表或类表数据类型是否可能 编辑 联合的游标计数实际上是 n 其中 n 是 1 2
  • 什么会导致 Oracle ROWID 更改?

    AFAIK Oracle 中的 ROWID 表示相应数据文件中记录的物理位置 在什么情况下记录的ROWID可能会改变 我所知道的一个是分区表上的更新 它将记录 移动 到另一个分区 还有其他情况吗 我们的大多数数据库都是 Oracle 10
  • Oracle - 获取星期几

    今天是星期二 为什么当我运行这个 SQL 语句时 它说今天不是星期二 SELECT CASE WHEN TO CHAR sysdate Day Tuesday THEN Its Tuesday ELSE Its Not Tuesday EN
  • Oracle如何将UTC时间转换为本地时间(缺少偏移信息)

    我有一个包含日期列的表 我认为该列中的日期是以 UTC 格式保存的 我希望检索日期时以当地时间打印 这意味着当我从德国调用日期时 结果应该是这样的 2015 04 29 11 24 06 0200UTC EUROPE BERLIN 我尝试了
  • 具有连字符的 Oracle 正则表达式在 Windows 上给出的结果与在 Unix 上不同

    我有以下带有正则表达式的查询 select REGEXP REPLACE TEST 3304 V2 lt gt as REG from dual 当通过 SQL Plus 在Windows机器返回以下内容 SQL gt select REG
  • 自动提取数据 - Oracle SQL Developer

    我通过 SQL Developer 连接到 Oracle 数据库 我想编写一个返回每月数据集的查询 然后将该数据提取到分隔文本文件中 我知道如何做到这一点就好了 我想知道是否有一种方法可以编写一个脚本来运行查询并在一年内逐月提取数据 这样我
  • SQL 错误:ORA-14006:无效的分区名称

    我正在尝试使用以下 SQL 语句对 Oracle 12C R1 中的现有表进行分区 ALTER TABLE TABLE NAME MODIFY PARTITION BY RANGE DATE COLUMN NAME INTERVAL NUM
  • 根据由另一列分组的不同列的最大值获取值[重复]

    这个问题在这里已经有答案了 我想根据由另一列分组的不同列的最大值来获取列的值 我有这张表 KEY NUM VAL A 1 AB B 1 CD B 2 EF C 2 GH C 3 HI D 1 JK D 3 LM 并想要这样的结果 KEY V

随机推荐