关于db2索引(二)

来源:互联网 发布:net域名是什么意思 编辑:程序博客网 时间:2024/06/13 05:01

现在让我们来举一个例子。表7-1是一张User表

t71.JPG

如果在这个表上有一个建在User Id字段上的索引,该索引的逻辑结构就类似图7-5所示。

7.5.JPG

通过这个索引,用户要查找一个User ID=28的电话,需要在索引的根节点中找到中间的指针,然后读取叶节点找到28,然后根据28所包含的RID找到对应的的页面与偏移位置,快速地得到该行用户数据。

想象一下,如果这个表包含100万行,在没有索引的情况下,要查找User ID=28,就需要扫描整个表(表扫描)。但是当索引存在时,只需要读取几个索引数据页就可以找到RID,然后访问相应的数据页面读取数据,大大减少了I/O读次数。

那么一个合适的索引是什么概念呢?当判断一个索引是否应该(或者能否)被使用时,一方面应该看这个B+树所包含的数值,另一方面则需要判断该索引能够以极少的访问过滤大部分数据。比如,在图7-5中,如果用户通过Name查找,那么使用User ID定义的索引则毫无意义,因为该索引中每一个节点为User ID。这时,可考虑在Name列上创建另外一个索引。

如何判断一个索引是否能够过滤大部分数据呢?拿表7-2为例,同样在User ID上面创建索引,该索引中仅包含一个键值,而该键值中包含4个RID指向这个表中所有的行。这时DB2可能不会选择索引,因为索引的代价比表扫描还要大。

t72.JPG

也就是说,用户定义了索引后,并不能够保证这个索引每次访问都会被使用。DB2的优化器会判定使用索引是否能够提高效率,如果判定索引的效率不如扫描全表,DB2会使用全表扫描而不是索引扫描(这部分会在优化器章节再次阐述)。

索引键可以包含多个字段,这种索引叫做复合索引。在复合索引中,首先按照第一个键值排序,如果第一个键相同而第二个键不同,则按照第二个键排序,以此类推。

t73.JPG

如果在Make与Model字段创建索引,那么索引的结构如图7-6所示。首先按照Make(制造商)排序,当Make相同时,再按照Model排序,如Honda Civic就排在Honda Accord之后。

7.6.JPG

需要注意的是,如果在(A,B)字段上创建一个索引,当查询条件包含A,或者A与B,那么可以有效地使用索引。但是如果条件中仅仅包含B,那么索引并不能带来效率上的提升。在以上汽车的例子中,如果用户想查询Model=’Civic’的行,DB2并不会使用在(Make,Model)上创建的索引。因此,当创建索引时一定要特别注意索引中的列顺序,在(Make,Model)和在(Model,Make)列上创建的索引完全不同。

以下我们看一下索引创建的语法:

(1)        create index idx_album_itemno on albums (itemno)
(2)        create unique index dba.empno on dba.employee (empno asc)
(3)        create index item on stock (itemno) cluster
(4)        create unique index empidx on employee (empno) include (lastname, firstname)
(5)        create index name on employee(firstname, lastname) 

第(1)条语句在albums表的itemno字段创建了一个普通索引。

第(2)条语句在employee表的empno字段创建了唯一性索引。Unique表示唯一性索引,当在表上创建了主键或唯一键时,会自动创建唯一性索引。

第(3)条语句指定了Cluster选项,Cluster表示集群或簇的意思,目的是尽量保持数据页的物理顺序和索引键顺序保持一致。缺省情况下,表数据的物理组织是无序的,数据可能杂乱无章地分散在很多数据页中,这样当按照某个范围查询一组数据的话,就要根据索引叶子节点的RID映射到很多页中获取数据,如果数据量很大的话,需要的I/O是很大的。如果这些数据在物理上是连续的,那么叶子节点的RID可能指向相邻的数据页,这时数据的获取就更快捷,需要的页数也更少,效果更高。这就是Cluster索引的目的。

图7-7是Cluster索引与Non-Cluster索引的对比,当根据某个范围获取一组数据的时候,Cluster索引可能带来I/O效率上的巨大提升。

7.7.JPG

注意:对数据的增删改可能会造成数据物理顺序无法和索引键保持一致,可通过reorg对表和索引进行重组。

第(4)条语句指定了include选项。有些读者可能不熟悉该选项,其实在某些场景,include对效率的提升也很明显。举例来说,对于employee表,最经常访问的字段是员工号和姓名,如果在员工号上创建索引,当根据员工号查询姓名时,DB2会从索引中找到RID,然后从表中获取姓名,这至少需要2次I/O(索引页和数据页I/O)。当使用include 选项时,include字段会附加在索引键所指向的每一个RID上,这样就可以从索引中直接获取include字段,而不必读取数据页。本例中,姓名可以直接从索引中获得,而不需要通过RID读取表,但如果还想获取其它字段,就只能访问数据页了。注意:include也叫index-only访问,只有唯一性索引才可以使用该选项。

第(5)条语句创建了一个复合索引。

可以通过describe indexes for table <tabname> show detail 命令查看一个表是否有索引、在哪些字段上建的索引,以及索引的类型。也可以通过SYSCAT.INDEXES字典表查看索引信息

原创粉丝点击