索引概述

来源:互联网 发布:itoa函数在linux 编辑:程序博客网 时间:2024/05/29 04:24

索引是一种与表或表簇相关联的可选结构,有时可以提高数据访问速度。通过在表中的一个或多个列上创建索引,在某些情况下使您能够(快速地)从随机分布的表行中检索一小部分行。索引是减少磁盘 I/O 的许多手段之一。

如果一个堆组织表没有索引,数据库必须执行全表扫描来查找值。例如,如果没有索引,为查询hr.departments 表中的位置 2700,数据库需要搜索每个表块中的每一行,以找到该值。当数据量增加时,这种方法不具备良好的可扩展性。

通常,在下列情况下可以考虑在某列上创建索引:

 要索引的列经常被查询,并只返回表中的行的总数的一小部分。

 在索引的列或列集上存在引用完整性约束。索引可以避免当你更新父表主键、合并父表、从父表删除行时可能引起的全表锁定。

 要在表上设置唯一键约束,并且您想手动指定索引和所有索引选项。

索引特征

索引是一种模式对象,它在逻辑上和物理上都与其相关联的对象中的数据保持独立。因此,可以删除或创建索引而不会实际影响相关的表。

注意:

如果您删除一个索引,应用程序将仍然可以工作。不过,访问之前索引过数据可能变慢。

索引的存在与否,不需要改变任何 SQL 语句的写法。索引是到单一行数据的快速访问路径。它只影响执行的速度。对于一个已被索引的给定的数据值,索引直接指向包含该值的行的位置。

在创建索引后,数据库会自动维护并使用它们。数据库还会自动反映对相关表数据的更改,如添加、 更新、和删除行等,用户不需要对所有相关索引做任何操作。即使在插入行时,被索引数据的检索性能仍然几乎不变。但是,在表上存在过多的索引,会降低 DML 性能,因为数据库还必须更新索引。

索引具有以下属性:

 可用性

索引可能是可用的 (默认值) 或不可用的。不可用索引在DML 操作中不会被维护,并会被优化程序忽略。不可用索引可以提高大容量加载的性能。你不用删除索引并稍后重新创建它,你可以使索引不可用,最后再重新生成它。不可用索引或索引分区不会占用空间。当你把一个可用的索引置为不可用时,数据库将删除其索引段。

非函数索引:

--使索引不可用alter index index_name unusable;--重建索引alter index index_name rebuild;

函数索引:

--使索引不可用alter index index_name disable;--使索引可用alter index index_name enable;

 可见性

索引可能是可见的 (默认值) 或不可见的。不可见索引在 DML 操作中会被维护,但在默认情况下优化程序不会使用它。使索引不可见是使其不可用或删除它的一种替代方法。不可见索引有时特别有用,比如在删除索引前测试移除后果,或临时用一下索引而不会影响整个应用程序。

--使索引不可见alter index index_name invisible;--使索引可见alter index index_name visible;

键和列

键是一个列集或表达式,您可以在它上面创建索引。虽然这两个术语通常互换使用,但索引和键还是不同的。索引是存储在数据库中的一种结构,用户使用SQL 语句来管理它们而键严格来讲只是一个逻辑概念。

下面的语句在示例表oe.orders的列customer_id上创建索引:

CREATE INDEX ord_customer_ix ON orders(customer_id);

在前面的语句中, customer_id 列是索引键。索引本身被命名为 ord_customer_ix。

注意:

主键和唯一键会自动生成索引,但您可能还需要在外键上创建索引

复合索引

复合索引,也称为连接索引,是在某个表中的多个列上的索引。复合索引中的列应该以在检索数据的查询中最有意义的顺序出现,但在表中不必是相邻的。

若 WHERE 子句引用了复合索引中的所有列或前导列,复合索引可以加快 SELECT 语句的数据检索速度。所以,在定义中所使用的列顺序很重要。一般地,最常被访问的列放在前面。

例如,假定应用程序经常查询雇员表中的 last_name、 job_id 和薪金列。同时假定last_name有很高的基数,也就是相对于表的总行数来说,不同值的数目很大。按以下的列顺序创建索引:

CREATE INDEX employees_ixON employees (last_name, job_id, salary);

如果查询会访问所有的三个列,或仅 last_name 列,或仅 last_name 和 job_id 列,则会使用此索引。在本例中,不访问 last_name 列的查询,将不会使用索引。

注意:

在某些情况下,例如,若前导列的基数很低,则数据库可能使用索引跳跃扫描

在同一个表上可以存在多个索引,只要其索引列具有不同的排列顺序。如果您对多个列指定不同的排列顺序,您可以在这些相同的列上创建多个索引。例如,下面的 SQL 语句指定的排列都是有效的:

CREATE INDEX employee_idx1 ON employees (last_name, job_id);CREATE INDEX employee_idx2 ON employees (job_id, last_name);

唯一索引和非唯一索引

索引可以是唯一的或非唯一的。唯一索引保证在表的键列或键列集上没有具有重复的值的行。例如,没有任何两名雇员,可以有相同的雇员 id。因此,在一个唯一索引中,对每个数据值都存在一个 rowid。叶块中的数据仅根据键排序。

非唯一索引允许在索引的列或列集中有重复的值。例如,雇员表的 first_name 列中可能包含多个Mike值。对于非唯一索引,rowid 被包含在键中且已排序,因此非唯一索引按索引键和 rowid (升序) 进行排序。

除了位图索引或簇键列值为空的情况之外,Oracle 数据库不会索引所有键列都为空的表行。

索引类型

Oracle 数据库提供了几种索引模式,以提供增强性能的功能。索引可以分为以下几类:

 B-树索引

这是索引的标准类型。他们对于主键和高选择性索引非常适合。**在复合索引中使用时,B-树索引可以按多个索引列以排序方式检索数据。**B-树索引具有下列子类型:

o 索引组织表

索引组织表不同于堆组织表,因为数据本身就是索引。

o 反键索引

在这种类型的索引中,索引键中的字节被反转了,例如, 103被存储为 301。反转字节可以把对索引记录的插入分散到的很多数据块。

o 降序索引

这种类型的索引将存储在一个特定的列或多列中的数据按降序排序。

o B-树簇索引

这种类型的索引用于索引表簇键。它的键指向包含簇键相关行所在块,而不是指向行。

 位图索引和位图联接索引

在位图索引中,索引条目使用位图来指向多个行。相比之下, B-树索引条目指向单个行。位图联接索引是在两个或更多表的联接上的位图索引。

 基于函数的索引

这种类型的索引包括经过一个函数(如UPPER函数)转换过的列,或包括在表达式中的列B-树索引或位图索引都可以是基于函数的。

 应用程序域索引

这种类型的索引是由用户为一个特定的应用程序域中的数据创建的。其物理索引不需要使用传统的索引结构,可以存储为 Oracle 数据库表,或外部文件。

B-树索引

平衡树,简称B-树,是最常见的数据库索引类型。一个 B-树索引是被划分为多个范围的已排序的值列表。通过将键与一行或行范围关联起来 ,B-树可以对多种类型的查询提供优秀的检索性能,包括精确匹配和范围搜索等。

图 3-1 显示了一个 B-树索引的结构。该示例显示在department_id 列上的一个索引,它是雇员表的一个外键。

这里写图片描述

分支块和页块

B-树索引有两种类型的块: 用于查找的分支块和用于存储值的叶块B-树索引的上层分支块包含指向下层索引块的索引数据。在图 3-1 中,根分支块包含条目 0-40, 指向下一个分支级别中最左边的块。此分支块包含条目如 0-10 和 11-19等。每个这些条目指向包含在该范围内键值的叶块。

B-树索引之所以是平衡的,是因为所有叶块都自动处于相同的深度因此,在索引中从任意位置检索任意记录需要的时间基本上是相同的。索引的高度是从根块到叶块所需的块的数量。分支级别等于其高度减 1。在图3-1中,索引的高度为 3 ,分支级别为2。

分支块用于存储在两个键之间作出分支决定所需的最小键前缀这种技术使数据库在每个分支块上能够尽可能存放更多的数据。 分支块包含一个指针,该指针指向包含该键的子块键和指针的数量受限于块大小

叶块包含每个被索引的数据值,和一个相应的用来定位实际行的rowid每个条目按 (rowid,键)排序在一个叶块内,键和 rowid 链接到其左右同级条目这些叶块本身也双向链接在一起。如图 3-1 ,最左边的叶块 (0-10) 链接到第二个叶块 (11-19)。

注意:

在字符数据列上的索引,基于数据库字符集中字符的二进制值

索引扫描

在索引扫描中,数据库使用语句指定的索引列,通过遍历索引来检索行。数据库扫描索引,将使用n个I/O就能找到其要查找的值,其中 n 即是B-树索引的高度。这是数据库索引背后的基本原理

如果 SQL 语句仅访问被索引的列,那么数据库只需直接从索引中读取值,而不用读取表如果该语句同时还需要访问除索引列之外的列,那么数据库会使用 rowids 来查找表中的行通常,为检索表数据,数据库以交替方式先读取索引块,然后读取相应的表块。

完全索引扫描

在完全索引扫描中,数据库顺序读取整个索引如果在 SQL 语句中的谓词 (WHERE 子句) 引用了一个索引列,或者在某些情况下未不指定任何谓词,此时可能使用完全索引扫描完全扫描可以消除排序,因为数据本身就是基于索引键排过序的。

假设应用程序运行以下查询:

SELECT department_id, last_name, salaryFROM employeesWHERE salary > 5000ORDER BY department_id, last_name;

此外假定 department_id last_name,和salary是一个复合索引键。Oracle 数据库会执行完全索引扫描,按顺序读取 (按部门 ID 和姓氏顺序) 并基于薪金属性进行筛选。通过这种方式,数据库只需扫描一个小于雇员表的数据集,而不用扫描那些未包含在查询中的列,并避免了对该数据进行排序。

快速完全索引扫描

快速完全索引扫描是一种完全索引扫描,数据库并不按特定的顺序读取索引块数据库仅访问索引本身中的数据,而无需访问表。

当索引包含了查询所需的所有列,且索引键中至少一列具有 NOT NULL 约束时,快速完全索引扫描可以替代全表扫描

例如,应用程序发出以下查询,不包含 ORDER BY 子句:

SELECT last_name, salaryFROM employees;

如果姓氏和工资是一个复合索引键,那么快速完全索引扫描只需读取索引条目,就可以获取所需的信息。

索引范围扫描

索引范围扫描是对索引的有序扫描,具有以下特点:

在条件中指定了一个或多个索引前导列。条件指定一个或多个表达式和逻辑 (布尔) 运算符的组合,并返回一个值( TRUE、 FALSE,或UNKNOWN)

一个索引键可能对应0个、1个或更多个值

通常,数据库使用索引范围扫描来访问选择性的数据选择性是查询所选择的数据占总行数的百分比, 0 意味着没有任何行,1 表示所有行选择性与一个(或多个)查询谓词相关,比如WHERE last_name LIKE ‘A%’。值越接近 0的谓词越具有选择性,相反,越接近1的谓词则越不具有选择性。

例如,用户查询姓氏以A开头的雇员。假定 last_name 列已被索引,其索引条目如下所示:

Abel,rowidAnde,rowidAnde,rowidAtkinson,rowidAtkinson,rowidAustin,rowidAustin,rowidAustin,rowidAustin,rowidBaer,rowidBaer,rowid..

数据库可以使用范围扫描,因为在谓词中指定了last_name列,而且每个索引键可能对应多个rowids。例如有两个雇员名叫Austin,所以有两个 rowids 都与索引键Austin相关联。

索引范围扫描可以在两边都有边界,比如部门ID在10 至 40之间的查询,或只在一边有界,比如部门 id在40以上的查询。为扫描索引,数据库将在叶块之间前后移动。例如,对于ID在10 到 40之间的扫描,将先定位到包含最低键值(大于或等于10)的第一个索引叶块。然后顺着各个被链接的页结点水平推进,直到它找到一个大于 40 的值为止。

唯一索引扫描

相对于索引范围扫描,唯一索引扫描必须是 有0个 或 1个 rowid 与索引键相关联当一个谓词使用相等运算符引用了唯一索引键的所有列时,数据库将执行唯一扫描只要找到了第一个记录,唯一索引扫描就停止处理,因为不可能有第二个记录满足条件。

作为演示,假定用户运行如下查询:

SELECT *FROM employeesWHERE employee_id = 5;

假定 employee_id 列是主键,在这种情况下,数据库可以使用唯一索引扫描来定位rowid,以找到 ID 为 5 的雇员

索引跳跃扫描

索引跳跃扫描使用复合索引的逻辑子索引。数据库“跳跃地”通过单个索引,好像它在多个单独的索引中搜索一样。如果在复合索引前导键列中有少量不同值,而在非前导键列中有大量不同值,此时使用跳跃扫描是有益的。

当在查询谓词中未指定组合索引的前导列时,数据库可能选择索引跳跃扫描。例如,假定您要在 sh.customers 表中查找一个客户,运行如下查询:

SELECT * FROM sh.customers WHERE cust_email = 'Abbey@company.com';

customers表中有一列 cust_gender,其值为 M 或F。假定在列cust_gender和 cust_email上存在一个复合索引。示例3-1 显示了索引条目的一部分。

虽然未在 WHERE 子句中指定 cust_gender,数据库可以使用跳跃索引扫描。

在跳跃扫描中,逻辑子索引的数目决定于前导列中的非重复值的数目。上述中前导列中有两个可能值。数据库在逻辑上将该索引拆分为一个具有 F 键的子索引和另一个具有M键的子索引。

当搜索电子邮件为 Abbey@company.com的客户的记录时, 数据库首先搜索 F值的子索引,然后搜索M值的子索引。从概念上讲,数据库这样处理查询,如下所示:

SELECT * FROM sh.customers WHERE cust_gender = 'F'AND cust_email = 'Abbey@company.com'UNION ALLSELECT * FROM sh.customers WHERE cust_gender = 'M'AND cust_email = 'Abbey@company.com';

索引聚簇因子

索引聚簇因子用于测量相对于某个索引值(如雇员姓氏)的行顺序被索引值的行存储得越有序,则聚簇因子越低

作为一种粗略测量通过索引读取整个表所需的I/O数,聚簇因子非常有用:

 如果聚簇因子较高,则在大型索引范围扫描过程中,数据库将执行相对较高数目的I/O。索引条目指向随机表块,因此数据库可能必须一遍又一遍地来回重读索引所指向的同一数据块

 如果聚簇因子较低,则在大型索引范围扫描过程中数据库将执行相对较低数目的I/O。在一个范围内的索引键倾向于指向相同的数据块,因此该数据库不必来回重读相同的数据块。

聚簇因子与索引扫描关系密切,因为它可以显示:

 数据库是否会在大范围扫描中使用索引

 相对于索引键的表组织程度

如果行必须按索引键顺序排列,是否应考虑使用索引组织表、 分区、或表簇

示例 3-2 所示的查询,通过ALL_INDEXES 查看这两个索引的聚簇因子。EMP_NAME_IX 的聚簇因子较低,这意味着在一个单一叶块中的相邻索引条目倾向于指向同一个数据块中的行。EMP_EMP_ID_PK 的聚簇因子较高,这意味着在相同的叶块中的相邻索引条目不太可能指向同一个数据块中的行。

SQL> SELECT INDEX_NAME, CLUSTERING_FACTOR2 FROM ALL_INDEXES3 WHERE INDEX_NAME IN ('EMP_NAME_IX','EMP_EMP_ID_PK');INDEX_NAME CLUSTERING_FACTOR-------------------- -----------------EMP_EMP_ID_PK 19EMP_NAME_IX 2

反向键索引

反向键索引是一种B-树索引,它在物理上反转每个索引键的字节,但保持列顺序不变。例如,如果索引键是 20,,并且在一个标准的 B-树索引中此键被存为十六进制的两个字节C1 15, 那么反向键索引会将其存为 15,C1。

反向键解决了在 B-树索引右侧的的叶块争用问题。在 Oracle 真正应用集群 (Oracle RAC) 数据库中的多个实例重复不断地修改同一数据块时,这个问题尤为严重。例如,在订单表中,订单的主键是连续的。在集群中的一个实例添加订单 20,而另一个实例添加订单 21,每个实例都将它的键写入索引右侧的相同叶块。

在一个反向键索引中,对字节顺序反转,会将插入分散到索引中的所有叶块。例如键 20 和 21,本来在一个标准键索引中会相邻,现在存储在相隔很远的独立的块中。这样,顺序插入产生的 I/O被更均匀地分布了。

因为存储数据时,并没有按照键列排序,因此在某些情况下,反向键格式丧失了执行索引范围扫描查询的能力。例如,如果用户发出一个订单 id 大于 20的查询,但数据库不能从包含此 ID的块开始扫描并沿着叶块水平推进。

创建反向键索引:

create index index_name on table_name(column_name) reverse;

升序和降序索引

对于升序索引,数据库按升序排列的顺序存储数据默认情况下,字符数据按每个字节中包含的二进制值排序, 数值数据按从小到大排序,日期数据从早到晚排序。

举一个升序索引的例子,请考虑下面的 SQL 语句:

CREATE INDEX emp_deptid_ix ON hr.employees(department_id);

Oracle 数据库对 hr.employees 表按department_id 列进行排序。从 0 开始,按department_id列及相应的 rowid 值的升序顺序加载索引。使用此索引,数据库搜索已排序的 department_id 值,并使用相关联的 rowids 来定位包含所请求的 department_id 值的行。

通过在 CREATE INDEX 语句中指定DESC关键字,您可以创建一个降序索引。在这种情况下,索引在指定的一列或多列上按降序顺序存储数据。如果在图 3-1中employees.department_id 列上的索引为降序,则包含 250 的叶块会在树的左侧,而0在右侧。降序索引的默认搜索顺序是从最高值到最低值。

当要求查询按一些列升序而另一些列降序排序时,降序索引非常有用。例如,假定您在last_name 列和 department_id 列上创建一个复合索引,如下所示:

CREATE INDEX emp_name_dpt_ix ON hr.employees(last_name ASC, department_id DESC);

一个对hr.employees用户查询,要求按姓氏以升序顺序 (A 到 Z) 而部门 id 以降序 (从高到低)排序,则数据库可以使用此索引检索数据并避免额外的排序步骤。

键压缩

Oracle 数据库可以使用键压缩来压缩 B-树索引或索引组织表中的主键列值的部分。键压缩可以大大减少索引所使用的空间。

一般地,索引键包含两个片断,一个分组片断和一个唯一片断键压缩将索引键分成两部分,即作为分组片断的前缀条目和作为唯一或几乎唯一片断的后缀条目数据库通过在一个索引块中的多个后缀条目之间共享前缀条目来实现压缩。

注意:

如果某个键未被定义为具有唯一片断,那么数据库会通过将一个rowid 附加到分组片断来提供唯一片断

默认情况下,一个唯一索引的前缀由除最后一列之外的所有键列组成,而非唯一索引的前缀包含所有键列。例如,假设您在oe.orders 表上创建一个复合索引,如下所示:

CREATE INDEX orders_mod_stat_ix ON orders ( order_mode, order_status );

在 order_mode 和 order_status 列中有许多重复值出现。一个索引块中的条目可能如示例 3-3 中所示。

online,0,AAAPvCAAFAAAAFaAAaonline,0,AAAPvCAAFAAAAFaAAgonline,0,AAAPvCAAFAAAAFaAAlonline,2,AAAPvCAAFAAAAFaAAmonline,3,AAAPvCAAFAAAAFaAAqonline,3,AAAPvCAAFAAAAFaAAt

示例中,键前缀将包括 order_mode 和 order_status 的串联值。如果此索引按默认键压缩创建,那么重复键前缀(如online,0和 online,2)将会被压缩。从概念上讲,数据库按如下示例中所示实现压缩:

online,0AAAPvCAAFAAAAFaAAaAAAPvCAAFAAAAFaAAgAAAPvCAAFAAAAFaAAlonline,2AAAPvCAAFAAAAFaAAmonline,3AAAPvCAAFAAAAFaAAqAAAPvCAAFAAAAFaAAt

后缀条目形成索引行的压缩版本。每个后缀条目引用一个与其存储在相同索引块中的前缀条目。

或者,创建一个压缩索引时,您也可以指定前缀长度。例如,如果指定了前缀长度为 1 ,那么前缀将会是 order_mode,而后缀将会是 order_status,rowid。对于示例 3-3 中的数值,索引会提取重复出现的online作为前缀,如下所示:

online0,AAAPvCAAFAAAAFaAAa0,AAAPvCAAFAAAAFaAAg0,AAAPvCAAFAAAAFaAAl2,AAAPvCAAFAAAAFaAAm3,AAAPvCAAFAAAAFaAAq3,AAAPvCAAFAAAAFaAAt

对索引中的每个叶块,一个特定前缀最多被存储一次只有在B-树索引的叶块中的键会被压缩。在分支块中的键后缀可以被截断,但不会被压缩。

创建索引键压缩:

create index index_name on table_name(column_name) compress <前缀个数>;

位图索引

在位图索引中,数据库为每个索引键存储一个位图。在传统的 B-树索引中,一个索引条目指向单个行。在位图索引中,每个索引键存储指向多个行的指针。

位图索引主要用于数据仓库,或在以特定方式引用很多列的查询环境中。可能需要一个位图索引的情况包括:

索引列的基数较低,也就是说,不同值的数目相比表的总行数很小。

被索引的表是只读的,或DML 语句不会对其进行重大修改

举一个数据仓库的例子, sh.customer 表的 cust_gender 列只有两个可能的值:M和 F。假设会经常查询某一性别的客户数目。在这种情况下,可以考虑在customer.cust_gender 列上创建位图索引。

位图中的每一位对应于一个可能的 rowid。如果设置了某位,那么与其相应的 rowid 行包含该键值。映射函数将位的位置转换为一个实际的 rowid,所以,虽然位图索引使用不同的内部表示形式,但它提供了与B-树索引相同的功能。

如果更新了某个单行中的索引列,那么数据库将锁定整个索引键条目(例如 M 或 F) ,而不只是该位映射到的更新行。因为一个键指向多个行,DML通常会锁定索引数据的所有这些行。因此,位图索引并不适合许多 OLTP 应用程序。

单表的位图索引

与B-树索引不同,位图索引可以包括完全由空值组成的键。对空值建立索引对于某些的 SQL 语句是有用的,比如使用 COUNT 聚合函数的查询。

调查客户的人口趋势的分析人员可能会问,”我们的女性客户中,有多少是单身或离婚的?” 这一问题对应于以下的 SQL 查询:

SELECT COUNT(*)FROM customersWHERE cust_gender = 'F'AND cust_marital_status IN ('single', 'divorced');

位图索引可以高效地处理此查询,通过计算得到的位图作为插图表 3-3 在 1 值的数量。要确定满足条件的客户,数据库可以访问表使用得到的位图。
这里写图片描述

位图索引可以有效地合并与 WHERE 子句中的多个条件相对应的索引。满足一些但不是全部条件的行,将在表本身被访问之前被过滤掉。这种技术往往大大提高了响应的时间。

位图联接索引

位图联接索引是建立在两个或更多表的联接之上的位图索引。对于表列中的每个值,索引存储被索引表中的相应行的 rowid。相比之下,在标准位图索引中,索引是建立在一个表上的。

通过在联接前预先执行限制条件,位图联接索引是减少数据量的有效方式。举一个可能会用到位图联接索引的示例,假定用户经常查询某种特定职位类型的雇员数。一个典型的查询可能如下所示:

SELECT COUNT(*)FROM employees, jobsWHERE employees.job_id = jobs.job_idAND jobs.job_title = 'Accountant';

上述查询通常使用 jobs.job_title 上的一个索引来检索职位表中的Accountant行,然后通过(公共列)职位 ID,和员工表中employees.job_id列上的索引来找到匹配的行。若要从索引本身检索数据,而不是从表中扫描,您可以创建一个位图联接索引,如下所示:

CREATE BITMAP INDEX employees_bm_idxON employees (jobs.job_title)FROM employees, jobsWHERE employees.job_id = jobs.job_id;

如图 3-2 ,索引键是jobs.job_title, 而被索引的表是employees。

这里写图片描述

从概念上讲,employees_bm_idx 是建立在示例 3-5(包括示例输出)所示的SQL 查询中的 jobs.title 列上的索引。在索引中的 job_title 键指向雇员表中的行。对会计师数目的查询可以仅使用索引,而不用访问employees表和jobs表,因为该索引本身已包含所请求的信息。

例 3-5员工表和职位表的连接

SELECT jobs.job_title AS "jobs.job_title", employees.rowid AS "employees.rowid"FROM employees, jobsWHERE employees.job_id = jobs.job_idORDER BY job_title;jobs.job_title employees.rowid----------------------------------- ------------------Accountant AAAQNKAAFAAAABSAALAccountant AAAQNKAAFAAAABSAANAccountant AAAQNKAAFAAAABSAAMAccountant AAAQNKAAFAAAABSAAKAdministration Assistant AAAQNKAAFAAAABTAACAdministration Vice President AAAQNKAAFAAAABSAACAdministration Vice President AAAQNKAAFAAAABSAAB...

在数据仓库中,连接条件是在维度表主键列和事实数据表的外键列之间的一个等值连接 (使用相等运算符)。位图联接索引有时比物化视图的存储效率高得多,这是一种替代提前物化连接的方法。

位图存储结构

Oracle 数据库使用一个 B-树索引结构来为每个索引键存储位图。例如 ,如果jobs.job_title是一个位图索引的键列, 那么索引数据存储在一个 B-树中。单个位图存储在叶块中。

假定 jobs.job_title 列具有Shipping Clerk、Stock Clerk、及其他几个唯一值。此位图索引的索引条目具有以下组件:

 作为索引键的职位
 一个rowids范围的低值 rowid 和高值 rowid
 在该范围内的特定 rowids 的位图

从概念上讲,该索引中的一个索引叶块,可能包含如下所示的条目:

Shipping Clerk,AAAPzRAAFAAAABSABQ,AAAPzRAAFAAAABSABZ,0010000100Shipping Clerk,AAAPzRAAFAAAABSABa,AAAPzRAAFAAAABSABh,010010...

同一职位可能出现在多个条目中,这是因为其rowid 范围不同。

假定某个会话更新了一名雇员的职务 ID,从Shipping Clerk到Stock Clerk。在这种情况下,该会话需要对旧值(Shipping Clerk)和新值(Stock Clerk)所在索引键条目的独占访问权限。直到UPDATE提交之前,Oracle 数据库会锁定这两个条目所指向的所有行,而不是由Accountant或其他任何键所指向的行。

位图索引的数据存储在一个段中。Oracle 数据库将每个位图存储在一个或多个片断中。每个片断占一个单一数据块的一部分。

基于函数的索引

您可以基于函数、或涉及相关表的一个或多个列的表达式来创建索引。基于函数的索引计算函数或涉及一个或多个列的表达式的值,并将其存储在索引中。基于函数的索引可以是一个 B-树索引或位图索引。

用于生成索引的函数可以是算术表达式,或一个包含SQL 函数、 用户定义 PL/SQL 函数、 包函数,或 C 调用的表达式。 例如,函数可以将两个列中的值相加。

使用基于函数的索引

基于函数的索引对于在 WHERE 子句中包含函数计算的语句是有效的仅当在查询中包含该函数时,数据库才使用基于函数的索引。当数据库处理INSERT和 UPDATE语句时,它仍然必须计算函数才能完成对语句的处理。

例如,假设您创建如下基于函数的索引:

CREATE INDEX emp_total_sal_idxON employees (12 * salary * commission_pct, salary, commission_pct);

示例包含算术表达式的查询

SELECT employee_id, last_name, first_name,12*salary*commission_pct AS "ANNUAL SAL"FROM employeesWHERE (12 * salary * commission_pct) < 30000ORDER BY "ANNUAL SAL" DESC;

基于SQL 函数 UPPER(column_name) 或 LOWER(column_name)定义的索引,使对大小写无关的搜索变得非常方便。例如,假设雇员表的 first_name 列包含混合大小写字符。您在 hr.employees 表上创建了如下基于函数的索引:

CREATE INDEX emp_fname_uppercase_idxON employees ( UPPER(first_name) );

emp_fname_uppercase_idx 索引使如下所示的查询变得非常方便:

SELECT *FROM employeesWHERE UPPER(first_name) = 'AUDREY';

基于函数的索引对于只在一个表中的特定行上建立索引也是有用的。例如 sh.customers 表中的 cust_valid 列有I 或 A 两个值。如果只想对含A值的行建立索引,您可以编写一个函数,让不含A值的其它任何行都返回一个空值。可以这样创建索引,如下所示:

CREATE INDEX cust_valid_idxON customers ( CASE cust_valid WHEN 'A' THEN 'A' END );

优化基于函数的索引

对于在WHERE 子句中包含表达式的查询,优化程序可以在一个基于函数的索引上使用索引范围扫描。当谓词(WHERE 子句)的选择性很低时,范围扫描的访问路径显得特别有优势。示例 3-6 中,如果索引是基于表达式 12*salary*commission_pct来创建的,则优化程序可以使用索引范围扫描。

虚拟列可用于快速访问由表达式生成的数据。例如,您可以为表达式12*salary*commission_pct定义虚拟列 annual_sal,并在该 annual_sal列上创建一个基于函数的索引。

优化程序通过分析在 SQL 语句中的表达式来执行表达式匹配,然后比较的语句表达式目录树和基于函数的索引。这种比较不区分大小写,并忽略空格。

0 0
原创粉丝点击