索引概述
索引是一种与表或表簇相关联的可选结构,有时可以提高数据访问速度。
打个比方,假设一个人力资源经理有一个搁放纸盒的架子。在框中包含雇员信息的文件夹随机放置在纸盒中。员工 Whalen (ID 200) 的文件夹是从 10 盒从底往上的盒子中的第 1 盒,而 King 是(ID 100) 的文件夹是从底往上的第 3 盒。要查找某个文件夹,经理从底往上查看这些盒子中的每个文件夹,看完一盒又看下一盒,直到找到该文件夹。为加快查找速度,经理可创建一个索引,按顺序列出每个雇员 ID 和它的文件夹位置:
ID 100: Box 3, position 1 (bottom)
ID 101: Box 7, position 8
ID 200: Box 1, position 10
.
.
.
同样,经理可以为雇员姓氏,部门 id 等创建单独的索引。
索引的优缺点
索引的存在与否,不需要改变任何 SQL 语句的写法。
索引是对单行数据的快速访问路径。它只影响执行的速度。给定一个已索引的数据值,索引将直接指向包含该值的行的位置。
当一个索引存在于表的一个或多个列上时,数据库可以在一些情况下从随机分布的表行中检索一小部分行。索引是减少磁盘 I/O 的许多手段之一。如果一个堆组织表没有索引,数据库必须执行全表扫描来查找值。例如,如果没有索引,为查询 hr.departments 表中的位置 2700,数据库需要搜索每个表块中的每一行,以找到该值。当数据量增加时,这种方法不具备良好的可扩展性。
索引的缺点包含如下项:
-
手动创建索引通常需要对数据模型、应用程序和数据分布有深入的了解。
-
随着数据的变化,您必须重新考虑以前关于索引的决策。索引可能不再有用,或者可能需要新的索引。
-
索引占用磁盘空间。
-
当索引数据上发生DML时,数据库必须更新索引,这会造成性能开销。
通常,在下列情况下可以考虑在某列上创建索引:
-
要索引的列经常被查询, 并只返回表中的行的总数的一小部分。
- 在索引的列或列集上存在引用完整性约束。 索引可以避免当你更新父表主键、合并父表、从父表删除行时可能引起的全表锁定。
-
要在表上设置唯一键约束,并且您想手动指定索引和所有索引选项。
另见:
-
《Oracle Database Administrator’s Guide》了解有关自动索引的更多信息
-
《Oracle Database Licensing Information User Manual》有关不同版本和服务支持哪些特性的详细信息
索引可用性和可见性
索引可用(默认)或不可用,可见(默认)或不可见。
这些属性的定义如下:
-
可用性
不可用索引在 DML 操作中不会被维护,并会被优化程序忽略。 不可用索引可以提高大容量加载的性能。 你不用删除索引并稍后重新创建它,你可以使索引不可用, 最后再重新生成它。 不可用索引或索引分区不会占用空间。当你把一个可用的索引置为不可用时,数据库将删除其索引段。 -
可见性
不可见索引在 DML 操作中会被维护,但在默认情况下优化程序不会使用它。使索引不可见是使其不可用或删除它的一种替代方法。不可见索引有时特别有用,比如在删除索引前测试移除后果,或临时用一下索引而不会影响整个应用程序。
另见:
"Overview of the Optimizer"了解优化器如何选择执行计划
键和列
键是一个列集或表达式,您可以在它上面创建索引。
下面的语句在示例表 oe.orders 的列 customer_id 上创建索引:
CREATE INDEX ord_customer_ix ON orders (customer_id);
另见:
-
《Oracle Database SQL Language Reference》关于 CREATE INDEX 的语法和语义
复合索引
复合索引,也称为连接索引,是在某个表中的多个列上的索引。
复合索引中的列应该以在检索数据的查询中最有意义的顺序出现,但在表中不必是相邻的。
若 WHERE 子句引用了复合索引中的所有列或前导列,复合索引可以加快SELECT 语句的数据检索速度。所以,在定义中所使用的列顺序很重要。一般地,最常被访问的列放在前面。
CREATE INDEX employees_ix
ON employees (last_name, job_id, salary);
当多个索引满足以下任一条件时,它们可以以相同的列顺序存在于同一个表中:
-
索引的类型不同。
例如,您可以在相同的列上创建位图和b树索引。
-
索引使用不同的分区方案。
例如,您可以创建本地分区的索引和全局分区的索引。
-
索引具有不同的唯一性。
例如,您可以在同一列集上创建惟一索引和非惟一索引。
例如,对于相同的表列,可以以相同的顺序存在非分区索引、全局分区索引和本地分区索引。在同一时间内,只有一个列数相同、顺序相同的索引是可见的。
此功能使您能够迁移应用程序,而不需要删除现有索引并使用不同的属性重新创建它。此外,当索引键不断增加,导致数据库将新条目插入同一组索引块时,此功能在OLTP数据库中非常有用。为了缓解这种“热点”,可以将索引从非分区索引演化为全局分区索引。
如果同一列集中的索引在类型或分区模式上没有差异,那么这些索引必须使用不同的列排列。例如,下面的 SQL 语句指定的排列都是有效的:
CREATE INDEX employee_idx1 ON employees (last_name, job_id);
CREATE INDEX employee_idx2 ON employees (job_id, last_name);
另见:
《Oracle Database SQL Tuning Guide》有关使用复合索引的详细信息
唯一索引和非唯一索引
例如,没有任何两名雇员,可以有相同的雇员 id。在一个唯一索引中,对每个数据值都存在一个 rowid。叶块中的数据仅根据键排序
索引类型
Oracle 数据库提供了几种索引模式, 以提供增强性能的功能。
这是索引的标准类型。他们对于主键和高选择性索引(每个索引条目对应的行很少)非常适合。在复合索引中使用时, B-树索引可以按多个索引列以排序方式检索数据。b树索引的子类型如下表所示。
表 3-1 B-Tree 索引子类
B-Tree 索引子类 | 描述 | 参考 |
---|---|---|
索引组织表 | 索引组织表不同于堆组织表,因为数据本身就是索引。 | |
反键索引 |
在这种类型的索引中,索引键中的字节被反转了,例如, 103 被存储为 301。反转字节可以把对索引记录的插入分散到的很多数据块。
| |
降序索引 |
这种类型的索引将存储在一个特定的列或多列中的数据按降序排序。
| |
B-树簇索引 | 这种类型的索引将数据按降序存储在一个或多个特定的列上。 |
下表显示了不使用b树结构的索引类型。
表 3-2 不使用 B-Tree 结构的索引
类型 | 描述 | 参考 |
---|---|---|
位图索引和位图联接索引 |
在位图索引中,索引条目使用位图来指向多个行。相比之下, B-树索引条目指向单个行。位图联接索引是在两个或更多表的联接上的位图索引。
| |
基于函数的索引 |
这种类型的索引包括经过一个函数(如 UPPER 函数)转换过的列,或包括在表达式中的列。 B-树索引或位图索引都可以是基于函数的。
| |
应用程序域索引 |
这种类型的索引是由用户为一个特定的应用程序域中的数据创建的。其物理索引不需要使用传统的索引结构,可以存储为 Oracle 数据库表,或外部文件。
|
另见:
-
《Oracle Database Administrator’s Guide》了解如何管理索引
-
《Oracle Database SQL Tuning Guide》了解不同的索引类型
数据库如何维护索引
索引自动将数据更改反映到其底层表。更改的示例包括添加、更新和删除行。不需要用户操作。
即使插入行,索引数据的检索性能也几乎保持不变。但是,表上存在许多索引会降低DML性能,因为数据库还必须更新索引。
另见:
-
《Oracle Database Administrator’s Guide》了解有关自动索引的更多信息
-
《Oracle Database Licensing Information User Manual》有关不同版本和服务支持哪些特性的详细信息
索引存储
Oracle 数据库将索引数据存储在一个索引段中。
另见:
"Overview of Index Blocks"了解索引块的类型(根、分支和叶),以及索引项如何存储在块中
B-树索引概述
下图显示了一个 B-树索引的结构。该示例显示在 department_id 列上的一个索引,它是雇员表的一个外键。
分支块和页块
索引扫描
另见:
《Oracle Database SQL Tuning Guide》有关索引扫描的详细信息
完全索引扫描
例 3-1 全索引扫描
假设应用程序运行以下查询:
SELECT department_id, last_name, salary
FROM employees
WHERE salary > 5000
ORDER BY department_id, last_name;
在这个实例中,department_id last_name,和 salary 是一个复合索引键。 Oracle 数据库会执行完全索引扫描, 按顺序读取 (按部门 ID 和姓氏顺序) 并基于薪金属性进行筛选。通过这种方式, 数据库只需扫描一个小于雇员表的数据集,而不用扫描那些未包含在查询中的列,并避免了对该数据进行排序。
完全扫描可能这样读取索引条目,如下所示:
50,Atkinson,2800,rowid
60,Austin,4800,rowid
70,Baer,10000,rowid
80,Abel,11000,rowid
80,Ande,6400,rowid
110,Austin,7200,rowid
.
.
.
快速完全索引扫描
快速完全索引扫描是一种完全索引扫描,数据库仅访问索引本身中的数据,而无需访问表。数据库并不按特定的顺序读取索引块。
当满足以下两个条件时,快速全索引扫描可以替代全表扫描:
-
索引必须包含查询所需的所有列。
-
查询结果集中不能出现包含所有空值的行。要保证该结果,索引中至少有一列必须具有以下两种情况:
-
NOT NULL 约束
-
应用于列的谓词,避免查询结果集中考虑 null
-
例 3-2 快速全索引扫描
例如,应用程序发出以下查询, 不包含 ORDER BY 子句:
SELECT last_name, salary
FROM employees;
如果 last_name
列有一个 not null 约束。如果姓氏和工资是一个复合索引键,那么快速完全索引扫描只需读取索引条目,就可以获取所需的信息:
Baida,2900,rowid
Atkinson,2800,rowid
Zlotkey,10500,rowid
Austin,7200,rowid
Baer,10000,rowid
Austin,4800,rowid
.
.
.
索引范围扫描
索引范围扫描是索引的有序扫描,其中条件中指定了一个或多个索引前导列,一个索引键可能对应 0 个、 1 个或更多个值。
Abel,rowid
Ande,rowid
Atkinson,rowid
Austin,rowid
Austin,rowid
Baer,rowid
.
.
.
唯一索引扫描
作为演示,假定用户运行如下查询:
SELECT *
FROM employees
WHERE employee_id = 5;
假定 employee_id 列是主键,并具有如下的索引条目:
1,rowid
2,rowid
4,rowid
5,rowid
6,rowid
.
.
.
索引跳跃扫描
例 3-3 复合索引跳跃扫描
假定您要在 sh.customers 表中查找一个客户,运行如下查询:
SELECT * FROM sh.customers WHERE cust_email = 'Abbey@company.example.com';
F,Wolf@company.example.com,rowid
F,Wolsey@company.example.com,rowid
F,Wood@company.example.com,rowid
F,Woodman@company.example.com,rowid
F,Yang@company.example.com,rowid
F,Zimmerman@company.example.com,rowid
M,Abbassi@company.example.com,rowid
M,Abbey@company.example.com,rowid
逻辑子索引的数目决定于前导列中的非重复值的数目。在上述例子中,前导列中有两个可能值。数据库在逻辑上将该索引拆分为一个具有 F 键的子索引和另一个具有 M 键的子索引。
SELECT * FROM sh.customers WHERE cust_gender = 'F'
AND cust_email = 'Abbey@company.example.com'
UNION ALL
SELECT * FROM sh.customers WHERE cust_gender = 'M'
AND cust_email = 'Abbey@company.example.com';
另见:
《Oracle Database SQL Tuning Guide》了解跳跃扫描的更多信息
索引聚簇因子
索引聚簇因子用于测量相对于某个索引值(如雇员姓氏) 的行顺序。随着有序程度的增加,聚簇因子随之减少。
作为一种粗略测量通过索引读取整个表所需的 I/O 数,聚簇因子非常有用:
- 如果聚簇因子较高, 则在大型索引范围扫描过程中, 数据库将执行相对较高数目的 I/O。索引条目指向随机表块,因此数据库可能必须一遍又一遍地来回重读索引所指向的同一数据块。
-
如果聚簇因子较低, 则在大型索引范围扫描过程中数据库将执行相对较低数目的 I/O。在一个范围内的索引键倾向于指向相同的数据块,因此该数据库不必来回重读相同的数据块。
聚簇因子与索引扫描关系密切,因为它可以显示:
-
数据库是否会在大范围扫描中使用索引
-
相对于索引键的表组织程度
- 如果行必须按索引键顺序排列,是否应考虑使用索引组织表、 分区、 或表簇
例 3-4 聚簇因子
假定雇员表存放在两个数据块中。表 3-3 描述了两个数据块中的行(省略号表示未显示的数据)。
表 3-3 雇员表中某两个数据块的内容
数据块 1 | 数据块 2 |
---|---|
| |
Abel,block1row1
Ande,block1row2
Atkinson,block1row3
Austin,block1row4
Baer,block1row5
.
.
.
100,block1row50
101,block2row1
102,block1row9
103,block2row19
104,block2row39
105,block1row4
.
.
.
下面语句所示的查询, 通过 ALL_INDEXES 查看这两个索引的聚簇因子。
SQL> SELECT INDEX_NAME, CLUSTERING_FACTOR
2 FROM ALL_INDEXES
3 WHERE INDEX_NAME IN ('EMP_NAME_IX','EMP_EMP_ID_PK');
INDEX_NAME CLUSTERING_FACTOR
-------------------- -----------------
EMP_EMP_ID_PK 19
EMP_NAME_IX 2
另见:
《Oracle Database Reference》了解 ALL_INDEXES
反向键索引
升序和降序索引
举一个升序索引的例子,请考虑下面的 SQL 语句:
CREATE INDEX emp_deptid_ix ON hr.employees(department_id);
CREATE INDEX emp_name_dpt_ix ON hr.employees(last_name ASC, department_id DESC);
另见:
-
《Oracle Database SQL Tuning Guide》了解升序和降序索引搜索的详细信息的
-
《Oracle Database SQL Language Reference》有关 CREATE INDEX ASC 和 DESC 选项的说明
索引压缩
为了减少索引中的空间,Oracle数据库可以使用不同的压缩算法。
前缀压缩
Oracle数据库可以使用前缀压缩(也称为键压缩)来压缩b树索引或索引组织表中的主键列值的部分。前缀压缩可以大大减少索引消耗的空间。
未压缩的索引项有一个片段。使用前缀压缩的索引项有两个部分:一个是前缀项,这是分组项;一个是后缀项,这是惟一的或几乎惟一的部分。数据库通过在索引块中的后缀项之间共享前缀项来实现压缩。
CREATE UNIQUE INDEX orders_mod_stat_ix ON orders ( order_mode, order_status );
在前面的示例中,索引键可能是online,0。rowid存储在条目的键数据部分,而不是键本身的一部分。
或者,假设您在相同的列上创建了一个非惟一索引:
CREATE INDEX orders_mod_stat_ix ON orders ( order_mode, order_status );
假设在 order_mode 和 order_status 列中有许多重复值出现。一个索引块中的条目可能如下例所示:
online,0,AAAPvCAAFAAAAFaAAa
online,0,AAAPvCAAFAAAAFaAAg
online,0,AAAPvCAAFAAAAFaAAl
online,2,AAAPvCAAFAAAAFaAAm
online,3,AAAPvCAAFAAAAFaAAq
online,3,AAAPvCAAFAAAAFaAAt
在上例中, the key prefix would consist of a concatenation of the order_mode
and order_status
values, as in online,0
. The suffix consists in the rowid, as in AAAPvCAAFAAAAFaAAa
. The rowid makes the whole index entry unique because a rowid is itself unique in the database.
If the index in the preceding example were created with default prefix compression (specified by the COMPRESS
keyword), 那么重复键前缀(如 online,0 和 online,2) 将会被压缩。从概念上讲,数据库按如下示例中所示实现压缩:
online,0
AAAPvCAAFAAAAFaAAa
AAAPvCAAFAAAAFaAAg
AAAPvCAAFAAAAFaAAl
online,2
AAAPvCAAFAAAAFaAAm
online,3
AAAPvCAAFAAAAFaAAq
AAAPvCAAFAAAAFaAAt
后缀条目(rowids)形成索引行的压缩版本。 每个后缀条目引用一个与其存储在相同索引块中的前缀条目。
online
0,AAAPvCAAFAAAAFaAAa
0,AAAPvCAAFAAAAFaAAg
0,AAAPvCAAFAAAAFaAAl
2,AAAPvCAAFAAAAFaAAm
3,AAAPvCAAFAAAAFaAAq
3,AAAPvCAAFAAAAFaAAt
另见:
-
《Oracle Database Administrator's Guide》学习如何使用压缩索引
-
《Oracle Database VLDB and Partitioning Guide》了解如何对分区索引使用前缀压缩
-
《Oracle Database SQL Language Reference》获取 CREATE INDEX 的 key_compression 子句的描述
高级索引压缩
从 Oracle Database 12c Release 1 (12.1.0.2) 开始,对于堆组织表上受支持的索引,高级索引压缩对传统的前缀压缩进行了改进。
高级索引压缩的优点
前缀压缩对所支持的索引类型、压缩比和易用性有限制。前缀压缩对每个块使用固定的重复键消除,而高级索引压缩对每个块使用自适应的重复键消除。高级索引压缩的主要优点是:
-
数据库使用许多内部算法,如列内级前缀、重复键消除和rowid压缩,自动为每个块选择最佳压缩。与前缀压缩不同,高级索引压缩不需要用户知道数据特征。
-
高级压缩对非惟一索引和惟一索引都有效。前缀压缩在一些非惟一索引上工作得很好,但在前导列没有很多重复的索引上,其比率较低。
-
压缩索引的使用方式与未压缩索引相同。索引支持相同的访问路径:惟一键查找、范围扫描和快速完整扫描。
-
索引可以从父表或包含表空间的表继承高级压缩。
高级索引压缩的原理
高级索引压缩在块级别工作,为每个块提供最佳的压缩。数据库使用以下技术:
-
在创建索引期间,当叶块满时,数据库会自动将该块压缩到最优级别。
-
由于DML而重新组织索引块时,如果数据库能够为传入的索引项创建足够的空间,则不会发生块分割。然而,在没有高级索引压缩的DML中,当块满时总是发生索引块分割。
高级索引压缩 HIGH选项
在Oracle数据库12c版本2(12.2)之前的版本中,高级索引压缩的唯一形式是LOW级别压缩(COMPRESS ADVANCED LOW)。现在还可以指定high compression (COMPRESS ADVANCED HIGH),这是默认值。高级索引压缩与 HIGH 选项提供了以下优点:
-
在大多数情况下提供更高的压缩比,同时也提高了访问索引的查询的性能
-
采用比高级LOW级别更复杂的压缩算法
-
将数据存储在压缩单元中,压缩单元是一种特殊的磁盘上格式
例 3-5 创建具有高级HIGH级别压缩的索引
这个示例支持对表 hr.employees 上的索引进行高级索引压缩:
CREATE INDEX hr.emp_mndp_ix
ON hr.employees(manager_id, department_id)
COMPRESS ADVANCED;
下面的查询显示了压缩的类型:
SELECT COMPRESSION FROM DBA_INDEXES WHERE INDEX_NAME ='EMP_MNDP_IX';
COMPRESSION
-------------
ADVANCED HIGH
另见:
-
《Oracle Database Administrator’s Guide》了解如何使用压缩索引
-
《Oracle Database SQL Language Reference》有关的 CREATE INDEX 的key_compression 子句的说明
-
《Oracle Database Reference》了解 ALL_INDEXES 视图
位图索引概述
-
索引列的基数较低, 也就是说, 不同值的数目相比表的总行数很小。
-
被索引的表是只读的, 或 DML 语句不会对其进行重大修改。
如果更新了某个单行中的索引列,那么数据库将锁定整个索引键条目(例如M 或 F) , 而不只是该位映射到的更新行。因为一个键指向多个行, DML通常会锁定索引数据的所有这些行。因此, 位图索引并不适合许多 OLTP 应用程序。
另见:
-
《Oracle Database SQL Tuning Guide》了解如何使用位图索引以增强性能
-
《Oracle Database Data Warehousing Guide》了解如何使用数据仓库中的位图索引
案例:单表的位图索引
在这个案例中,sh.customers 表中的某些列是创建位图索引的候选对象。
考虑以下查询:
SQL> SELECT cust_id, cust_last_name, cust_marital_status, cust_gender
2 FROM sh.customers
3 WHERE ROWNUM < 8 ORDER BY cust_id;
CUST_ID CUST_LAST_ CUST_MAR C
---------- ---------- -------- -
1 Kessel M
2 Koch F
3 Emmerson M
4 Hardy M
5 Gowen M
6 Charles single F
7 Ingram single F
7 rows selected.
表 3-4 说明了上例所示的 cust_gender 列的位图索引。它包括两个分别针对每个性别的单独位图。
表 3-4 一列的位图示例
Value | Row 1 | Row 2 | Row 3 | Row 4 | Row 5 | Row 6 | Row 7 |
---|---|---|---|---|---|---|---|
| 1 | 0 | 1 | 1 | 1 | 0 | 0 |
| 0 | 1 | 0 | 0 | 0 | 1 | 1 |
SELECT COUNT(*)
FROM customers
WHERE cust_gender = 'F'
AND cust_marital_status IN ('single', 'divorced');
位图索引可以高效地处理此查询,通过计算得到的位图作为插图表 3-5 在 1 值的数量。要确定满足条件的客户,数据库可以访问表使用得到的位图。
表 3-5 两列的位图示例
Value | Row 1 | Row 2 | Row 3 | Row 4 | Row 5 | Row 6 | Row 7 |
---|---|---|---|---|---|---|---|
| 1 | 0 | 1 | 1 | 1 | 0 | 0 |
| 0 | 1 | 0 | 0 | 0 | 1 | 1 |
| 0 | 0 | 0 | 0 | 0 | 1 | 1 |
| 0 | 0 | 0 | 0 | 0 | 0 | 0 |
| 0 | 0 | 0 | 0 | 0 | 1 | 1 |
位图联接索引
位图联接索引是建立在两个或更多表的联接之上的位图索引。
SELECT COUNT(*)
FROM employees, jobs
WHERE employees.job_id = jobs.job_id
AND jobs.job_title = 'Accountant';
CREATE BITMAP INDEX employees_bm_idx
ON employees (jobs.job_title)
FROM employees, jobs
WHERE employees.job_id = jobs.job_id;
如下图所示,索引键是 jobs.job_title, 而被索引的表是employees。
从概念上讲, employees_bm_idx 是建立在下例(包括示例输出) 所示的 SQL 查询中的 jobs.title 列上的索引。 在索引中的 job_title 键指向雇员表中的行。 对会计师数目的查询可以仅使用索引,而不用访问 employees表和 jobs 表,因为该索引本身已包含所请求的信息。
SELECT jobs.job_title AS "jobs.job_title", employees.rowid AS "employees.rowid"
FROM employees, jobs
WHERE employees.job_id = jobs.job_id
ORDER BY job_title;
jobs.job_title employees.rowid
----------------------------------- ------------------
Accountant AAAQNKAAFAAAABSAAL
Accountant AAAQNKAAFAAAABSAAN
Accountant AAAQNKAAFAAAABSAAM
Accountant AAAQNKAAFAAAABSAAJ
Accountant AAAQNKAAFAAAABSAAK
Accounting Manager AAAQNKAAFAAAABTAAH
Administration Assistant AAAQNKAAFAAAABTAAC
Administration Vice President AAAQNKAAFAAAABSAAC
Administration Vice President AAAQNKAAFAAAABSAAB
.
.
.
另见:
《Oracle Database Data Warehousing Guide》了解位图联合索引的详细信息
位图存储结构
Oracle 数据库使用一个 B-树索引结构来为每个索引键存储位图。
例 3-6 位图存储实例
-
作为索引键的职位
-
一个 rowids 范围的低值 rowid 和高值 rowid
-
在该范围内的特定 rowids 的位图
从概念上讲,该索引中的一个索引叶块, 可能包含如下所示的条目:
Shipping Clerk,AAAPzRAAFAAAABSABQ,AAAPzRAAFAAAABSABZ,0010000100
Shipping Clerk,AAAPzRAAFAAAABSABa,AAAPzRAAFAAAABSABh,010010
Stock Clerk,AAAPzRAAFAAAABSAAa,AAAPzRAAFAAAABSAAc,1001001100
Stock Clerk,AAAPzRAAFAAAABSAAd,AAAPzRAAFAAAABSAAt,0101001001
Stock Clerk,AAAPzRAAFAAAABSAAu,AAAPzRAAFAAAABSABz,100001
.
.
.
同一职位可能出现在多个条目中, 这是因为其 rowid 范围不同。
另见:
"User Segments"解释段的不同类型,以及如何创建段
基于函数的索引概述
另见:
-
《Oracle Database Administrator's Guide》了解如何创建基于函数的索引
-
《Oracle Database SQL Tuning Guide》有关使用基于函数的索引的详细信息
-
《Oracle Database SQL Language Reference》 了解基于函数的索引的限制和使用注意事项
CREATE INDEX emp_total_sal_idx
ON employees (12 * salary * commission_pct, salary, commission_pct);
数据库在处理以下查询(包括部分示例输出)时可以使用前面的索引:
SELECT employee_id, last_name, first_name,
12*salary*commission_pct AS "ANNUAL SAL"
FROM employees
WHERE (12 * salary * commission_pct) < 30000
ORDER BY "ANNUAL SAL" DESC;
EMPLOYEE_ID LAST_NAME FIRST_NAME ANNUAL SAL
----------- ------------------------- -------------------- ----------
159 Smith Lindsey 28800
151 Bernstein David 28500
152 Hall Peter 27000
160 Doran Louise 27000
175 Hutton Alyssa 26400
149 Zlotkey Eleni 25200
169 Bloom Harrison 24000
例 3-8 基于 SQL 函数 UPPER的索引
CREATE INDEX emp_fname_uppercase_idx
ON employees ( UPPER(first_name) );
emp_fname_uppercase_idx 索引使如下所示的查询变得非常方便:
SELECT *
FROM employees
WHERE UPPER(first_name) = 'AUDREY';
例 3-9 为表中的特定行建立索引
CREATE INDEX cust_valid_idx
ON customers ( CASE cust_valid WHEN 'A' THEN 'A' END );
另见:
-
《Oracle Database Globalization Support Guide》有关语言学索引的信息
-
《Oracle Database SQL Language Reference》了解 SQL 函数的更多信息
优化基于函数的索引
当谓词具有高度选择性,即选择相对较少的行时,范围扫描访问路径尤其有用。示例 3-7 中,如果索引是基于表达式 12*salary*commission_pct 来创建的,则优化程序可以使用索引范围扫描。
另见:
-
《Oracle Database SQL Tuning Guide》关于收集统计信息的详细信息
-
《Oracle Database Administrator’s Guide》了解如何向表中添加虚拟列
应用程序域索引概述
应用程序域索引是一个特定于应用程序的自定义索引。
可扩展的索引可以:
-
可以在自定义的、 复杂的数据类型(如文档、 空间数据、 图像、和 视频剪辑等)之上建立索引, 请参阅 "Unstructured Data"
-
使用专门的索引技术
另见:
《Oracle Database Data Cartridge Developer's Guide》关于在 Oracle 数据库可扩展性体系结构中使用数据模块的信息
索引组织表概述
当有关的数据片断必须存储在一起, 或数据必须按特定的顺序物理地存储。这种表的典型用途是用于信息检索、空间数据和OLAP应用程序。
另见:
-
"OLAP"
-
《Oracle Database Administrator’s Guide》了解如何管理组织索引表
-
《Oracle Database SQL Tuning Guide》了解如何使用索引组织表来提高性能
-
《Oracle Database SQL Language Reference》关于 CREATE TABLE ... ORGANIZATION INDEX 的语法和语义
索引组织表特征
数据库系统通过操作 B-树索引结构,来在索引组织表上执行所有操作。
下表总结了索引组织表和堆组织表之间的差异。
表 3-6 堆组织表和索引组织表的比较
对组织表 | 索引组织表 |
---|---|
由 rowid 唯一地标识行。 定义主键约束是可选选项。 |
主键唯一地标识行。必须定义主键约束。
|
允许在 ROWID 伪列中的物理 rowid上创建辅助索引。
|
允许在 ROWID 伪列中的逻辑 rowid 上创建辅助索引。
|
可直接由 rowid 访问单个行。 | 可间接通过主键访问单个行。 |
顺序全表扫描按一定顺序返回所有行。
|
完全索引扫描或快速完全索引扫描按一定顺序返回所有行
|
可与其他表一起存储在表簇中。 | 不能存储在表簇中。 |
可以包含一个 LONG 数据类型的列,和多个 LOB 数据类型的列。
|
可以包含 LOB 列, 但不能包含 LONG 列。
|
可以包含虚拟列 (只支持关系型堆表)。
| 不能包含虚拟列。 |
Example 3-10 Scan of Index-Organized Table
20,Marketing,201,1800
30,Purchasing,114,1700
索引组织表中的叶块 2 可能包含如下所示的条目:
50,Shipping,121,1500
60,IT,103,1400
按主键顺序对索引组织表行的扫描,依照如下顺序读取块:
-
Block 1
-
Block 2
例 3-11 扫描堆组织表
50,Shipping,121,1500
20,Marketing,201,1800
同一个表中块 2 包含的行,如下所示:
30,Purchasing,114,1700
60,IT,103,1400
20,AAAPeXAAFAAAAAyAAD
30,AAAPeXAAFAAAAAyAAA
50,AAAPeXAAFAAAAAyAAC
60,AAAPeXAAFAAAAAyAAB
按主键顺序对表行的扫描,依照如下顺序读取块:
-
Block 1
-
Block 2
-
Block 1
-
Block 2
因此,在此示例中的块 I/O 数目是在索引组织表示例中的 2 倍。
See Also:
- 以了解有关堆组织表的更多信息
- 以进一步了解片段和数据块之间的关系
索引组织表的行溢出区
在创建一个索引组织表时,您可以指定一个单独的段为行溢出区。
-
索引条目
本部分包含所有主键列的值、指向该行溢出部分的物理 rowid、 或(可选的) 几个非键列的值。这部分存储在索引段中。 -
溢出部分
此部分包含剩余的非键列的值。这部分存储在溢出存储区段中。
另见
-
《Oracle Database Administrator’s Guide》了解如何使用 CREATE TABLE 的OVERFLOW 子句设置行溢出区
-
《Oracle Database SQL Language Reference》关于 CREATE TABLE ... OVERFLOW 的语法和语义
索引组织表的辅助索引
辅助索引是一个建立在索引组织表上的索引。
Oracle 数据库使用叫做逻辑 rowids 的行标识符来访问索引组织表。逻辑的 rowid 是表主键的 base64 编码表示形式。逻辑 rowid 的长度取决于主键长度。
10,Administration,200,1700
20,Marketing,201,1800
30,Purchasing,114,1700
40,Human Resources,203,2400
1700,*BAFAJqoCwR/+
1700,*BAFAJqoCwQv+
1800,*BAFAJqoCwRX+
2400,*BAFAJqoCwSn+
另见:
-
"Rowid Data Types"了解ROWID的使用,以及ROWID伪列
- 了解为什么行迁移,以及为什么迁移会增加I/Os的数量
-
《Oracle Database Administrator’s Guide》了解如何在索引组织表上创建辅助索引
-
《Oracle Database VLDB and Partitioning Guide》了解如何在索引组织表分区上创建辅助索引
逻辑 Rowids 和物理猜想
辅助索引使用逻辑 rowids 来查找表行。
-
不用物理猜测,则访问包括两个索引扫描: 先是一个对辅助索引的扫描,然后是一个对主键索引的扫描。
-
使用物理猜测,则访问取决于其准确性:
-
如果物理猜测准确, 则访问包括一个辅助索引扫描, 和一个读取行所在数据块的额外 I/O。
-
如果物理猜测不准确,则访问包括一个辅助索引扫描, 和一个读取错误的数据块 I/O (即猜测所指出的), 再是一个按主键值对索引组织表的唯一索引扫描
-
索引组织表上的位图索引
另见:
"Rowids of Row Pieces"学习物理rowids和逻辑rowids之间的区别