赞
踩
索引是为了快速检索和定位数据行而创建的一种数据结构。索引是由表中索引列数据进行排序后的集合和指向这些值的物理标识(例如:ROWID 等聚集索引键)共同组成。在 DM 中,除了位图索引、位图连接索引、全文索引和空间索引外,索引数据都采用 B+ 树结构进行存储,在 DM 手册的其余地方都简称为 B 树。索引和表一样需要存储空间。
索引相当于一本书的目录,根据目录中的页码标识快速检索并定位到的查找内容。
索引可使 SQL 语句快速地定位到相关数据记录上。除了系统自动创建的聚集索引以外,其它索引均为可选项。
创建或删除一个索引,不会影响基表、数据库应用或其它索引。当插入、更改和删除相关表的行时,DM8 会自动管理索引。如果删除索引,所有的应用仍继续工作,但访问以前被索引了的数据时速度可能会变慢。
从不同的角度可将索引分为五大类。
从物理存储角度进行分类,可分为聚集索引和非聚集索引。
//创建表格T1,并插入数据。
CREATE TABLE T1 (ID int,NAME varchar(20),DEPARTMENT varchar(20));
INSERT INTO T1 VALUES(1,'Zhang San', 'A部');
INSERT INTO T1 VALUES(2,'Li Si', 'B部');
INSERT INTO T1 VALUES(3,'Wang Wu', 'C部');
INSERT INTO T1 VALUES(4,'Chen Liu', 'D部');
//创建聚集索引,索引键为ID。
CREATE CLUSTER INDEX C1 on T1(ID);
//创建非聚集索引,索引键为NAME。
CREATE INDEX S1 on T1(NAME);
//使用聚集索引进行查找
EXPLAIN SELECT * FROM T1 WHERE ID=2;
//使用非聚集索引进行查找
EXPLAIN SELECT ID FROM T1 WHERE NAME='Wang Wu';
//先使用非聚集索引进行查找,再通过非聚集索引关联上聚集索引进行二次查找
EXPLAIN SELECT DEPARTMENT FROM T1 WHERE NAME='Chen Liu';
从索引功能角度进行分类,可分为唯一索引、函数索引、位图索引、位图连接索引、全文索引、空间索引、数组索引、普通索引。
从虚实角度进行分类,可分为虚索引和实索引。
从索引键值的个数进行分类,可分为单列索引和复合索引。
从分区的角度进行分类,可分为全局索引和局部索引。全局索引和局部索引均为二级索引,专门用于水平分区表中。
当分区子表个数较多、索引列的选择率较好、没有使用分区裁剪优化等因素时,执行计划会倾向于使用全局索引进行查询。但由于全局索引的日常维护成本高于局部索引。因此用户可根据实际应用场景权衡利弊之后再在全局索引和局部索引中进行选择。
索引是与表相关的可选的结构(聚集索引除外),它能使对应于表的 SQL 语句执行得更快,因为有索引比没有索引能更快地定位信息。DM8 索引能提供访问表的数据的更快路径,可以不用重写任何查询而使用索引,其结果与不使用索引是一样的,但速度更快。
DM8 提供了几种最常见类型的索引,对不同场景有不同的功能,它们是:
一般情况下,在插入或装载了数据后,为表创建索引会更加有效率。如果在装载数据之前创建了一个或多个索引,那么在插入每行时 DM8 都必须更改和维护每个索引,使得插入效率降低。
使用下面的准则来决定何时创建索引:
选取表中的索引列时可以考虑以下几点:
在 CREATE INDEX 语句中列的排序会影响查询的性能。通常,将最常用的列放在最前面。
如果查询中有多个字段组合定位,则不应为每个字段单独创建索引,而应该创建一个组合索引。当两个或多个字段都是等值查询时,组合索引中各个列的前后关系是无关紧要的。但是如果是非等值查询时,要想有效利用组合索引,则应该按等值字段在前,非等值字段在后的原则创建组合索引,查询时只能利用一个非等值的字段。
一个表可以有任意数量的索引。但是,索引越多,修改表数据的开销就越大。当插入或删除行时,表上的所有索引也要被更改;更改一个列时,包含该列的所有索引也要被更改。因此,在从表中检索数据的速度和更新表的速度之间有一个折衷。例如,如果一个表主要仅用于读,则索引多就有好处;如果一个表经常被更新,则索引不宜多建。
创建索引之前先估计索引的大小能更好地促进规划和管理磁盘空间。可以用索引以及回滚段、重做日志文件的组合估计的大小来决定支持所期望的数据库所需的磁盘空间的大小。通过这些估计,就可以购买合适的硬件和做出其他正确的决定。
用单个索引估计的大小能更好地管理索引使用的磁盘空间。创建索引时,可以设置适当的存储参数,并改善使用该索引的应用的 I/O 性能。例如,假设在创建索引之前估计索引的最大大小,之后就可以在创建该索引时设置适当的存储参数,就能很少为表的数据段分配簇。并且,所有的该索引的数据都被保存在相对连续的磁盘空间扇区中,这就减少了使用该索引的磁盘 I/O 操作所需的时间。
可以在除临时表空间、日志表空间和回滚段表空间外的其他任何表空间中创建索引,也可以在其索引的表的相同或不同的表空间中创建索引。如果表及其索引使用相同的表空间 能更方便地对数据库进行管理(如表空间或文件备份)或保证应用的可用性,因为所有有关的数据总是在一起联机。然而,将表及其索引放在不同的表空间(在不同磁盘上)产生的性能比放在相同的表空间更好,因为这样做减少了磁盘竞争。但是将表及其索引放在不同的表空间时,如果一个表上某索引所在的表空间脱机了,则涉及这张表的 SQL 语句可能由于执行计划仍旧需要使用被脱机的索引而不能成功执行。
本节描述如何创建索引。用户必须具备该表的CREATE INDEX 数据库权限。
使用CREATE INDEX 语句显示地创建索引。例如:
CREATE INDEX idx_t1 ON t1(DEPARTMENT);
DM8 中表(列存储表和堆表除外)都是使用 B 树索引结构管理的,每一个普通表都有且仅有一个聚集索引,数据都通过聚集索引键排序,根据聚集索引键可以快速查询任何记录。
当建表语句未指定聚集索引键时,DM8 的默认聚集索引键是 ROWID。若指定索引键,表中数据都会根据指定索引键排序。
建表后,DM8 也可以用创建新聚集索引的方式来重建表数据,并按新的聚集索引排序。
**例:**先创建一个表,然后对其ID列创建聚簇索引
CREATE TABLE T2(ID INT , NAEM VARCHAR(10));
CREATE CLUSTER INDEX C_IDX_ID ON T2(ID);
新建聚集索引会重建这个表以及其所有索引,包括二级索引、函数索引,是一个代价非常大的操作。因此,最好在建表时就确定聚集索引键,或在表中数据比较少时新建聚集索引,而尽量不要对数据量非常大的表建立聚集索引。
创建聚集索引的约束条件:
(1)每张表中只允许有一个聚集索引,如果之前已经指定过 CLUSTER INDEX 或者指定了 CLUSTER PK,则用户新建立 CLUSTER INDEX 时系统会自动删除原先的聚集索引。但如果新建聚集索引时指定的创建方式(列,顺序)和之前的聚集索引一样,则会报错;
(2)指定 CLUSTER INDEX 操作需要重建表上的所有索引,包括 PK 索引;
(3)删除聚集索引时,缺省以 ROWID 排序,自动重建所有索引;
(4)若聚集索引是默认的 ROWID 索引,不允许删除;
(5)聚集索引不能应用到函数索引中;
(6)不能在列存储表上新建/删除聚集索引;
(7)建聚集索引语句不能含有 partition_clause 子句;
(8)在临时表上增删索引会使当前会话上临时 b 树数据丢失;、
(9)不支持在含有多媒体类型的表上新建聚集索引。
索引可以是唯一的或非唯一的。唯一索引可以保证表上不会有两行数据在键列上具有相同的值,非唯一索引不会在键列上施加这个限制。
可用 CREATE UNIQUE INDEX 语句来创建唯一索引。如:
CREATE UNIQUE INDEX U_IDX_NAEM ON T2(NAEM);
用户可以在希望的列上定义 UNIQUE 完整性约束,DM8 通过自动地在唯一键上定义一个唯一索引来保证 UNIQUE 完整性约束。
基于函数的索引促进了限定函数或表达式的返回值的查询,该函数或表达式的值被预先计算出来并存储在索引中。正确使用函数索引,可以带来以下好处:
创建更强有力的分类,例如可以用 UPPER 和 LOWER 函数执行区分大小写的分类;
预先计算出计算密集的函数的值,并在索引中将其分类。可以在索引中存储要经常访问的计算密集的函数,当需要访问值时,该值已经计算出来了。因此,极大地改善了查询的执行性能;
增加了优化器执行范围扫描而不是全表扫描的情况的数量。如:
CREATE TABLE T3(ID INT , ID1 INT, NAEM VARCHAR(10));
CREATE INDEX IDX_ID_PLUS_ID1 ON T3(ID+ID1);
因为该索引是建立在 column_a + column_b 之上的,所以优化器可以为该查询使用范围扫描。优化器根据该索引计算查询代价,如果代价最少,优化器就会选择该函数索引,column_a + column_b 就不会重复计算。
创建函数索引有以下约束条件:
位图索引主要针对含有大量相同值的列而创建。位图索引被广泛引用到数据仓库中,创建方式和普通索引一致,对低基数(不同的值很少)的列创建位图索引,能够有效提高基于该列的查询效率。且执行查询语句的 where 子句中带有 AND 和 OR 谓词时,效率更加明显。
如:
CREATE BITMAP INDEX B_IDX_NAME ON T3(NAEM);
位图索引具有以下约束:
(1)支持普通表、堆表和水平分区表创建位图索引;
(2)不支持对大字段创建位图索引;
(3)不支持对计算表达式列创建位图索引;
(4)不支持在 UNIQUE 列和 PRIMARY KEY 上创建位图索引;
(5)不支持对存在 CLUSTER KEY 的表创建位图索引;
(6)仅支持单列或者不超过 63 个组合列上创建位图索引;
(7)MPP 环境下不支持位图索引的创建;
(8)不支持快速装载建含有位图索引的表;
(9)不支持全局位图索引;
(10)包含位图索引的表不支持并发的插入、删除和更新操作。
位图连接索引是一种提高通过连接实现海量数据查询效率的有效方式,主要用于数据仓库环境中。区别于上一节所说的建立在单表上的位图索引,位图连接索引是针对两个或者多个表的连接而建立的位图索引,同时保存了连接的位图结果。对于索引列中的每一个值,位图连接索引在索引表中保存了对应行的 ROWID。
create bitmap index SALES_CUSTOMER_NAME_IDX on SALES.SALESORDER_HEADER(SALES.CUSTOMER.PERSONID) from SALES.CUSTOMER, SALES.SALESORDER_HEADER where SALES.CUSTOMER.CUSTOMERID = SALES.SALESORDER_HEADER.CUSTOMERID;
隐式创建方式只支持创建唯一索引。
DM8 通过在唯一键或主键上创建一个唯一索引来在表上实施 UNIQUE KEY 或 PRIMARY KEY 完整性约束。当启用约束时 DM8 自动创建该索引。如下面的语句会自动在表 emp 的 name 列上创建一个唯一索引。
CREATE TABLE T1(C1 INT, C2 INT, C3 INT);
ALTER TABLE T1 ADD CONSTRAINT PK_EMP_NAME PRIMARY KEY (C1);
如果 SQL 语句想使用某一个索引,则 SQL 语句的查询项和 WHERE 子句的过滤项中必须包含该索引的全部索引键。当同时包含了多个索引的索引键时,系统会选择一个最优的索引进行查询。例如:SQL 语句“SELECT A FROM T WHERE B=1; ”会使用建立在(A,B)列上的索引。
总体来说,最少的查找即可得到所需数据,即为最优索引。
下面用具体的示例进行介绍。
数据准备:
CREATE TABLE T2 (ID int,NAME varchar(20),DEPARTMENT varchar(20),SALARY INT);
CREATE CLUSTER INDEX S21 on T2(ID);
CREATE INDEX S22 on T2(NAME,DEPARTMENT);
CREATE INDEX S23 on T2(NAME);
CREATE INDEX S24 on T2(DEPARTMENT);
CREATE INDEX S25 on T2(SALARY);
例 1 使用聚集索引 S21
EXPLAIN SELECT SALARY FROM T2 WHERE ID=10;
例 2 使用非聚集索引 S22
查询语句想使用索引 S22,则 SELECT 查询项和 WHERE 子句过滤项需包含 S22 的全部索引键 NAME 和 DEPARTMENT。
EXPLAIN SELECT DEPARTMENT FROM T2 WHERE NAME LIKE'%Zhang' AND DEPARTMENT='A部门';
或
EXPLAIN SELECT DEPARTMENT FROM T2 WHERE NAME='Zhang San';
例 3 先使用非聚集索引 S23,再使用聚集索引
首先,在 SSEK 中使用 S23 非聚集索引进行扫描定位,得到 NAME;
其次,因为 SELECT * 中查询项太多,需要在 BLKUP2 中通过 S23 回到聚集索引上进行二次查找,得到*中的其它数据。
EXPLAIN SELECT * FROM T2 WHERE NAME='Zhang San';
当一个表经过大量的增删改操作后,表的数据在物理文件中可能存在大量碎片,从而影响访问速度。另外,当删除表的大量数据后,若不再对表执行插入操作,索引所处的段可能占用了大量并不使用的簇,从而浪费了存储空间。
可以使用重建索引来对索引的数据进行重组,使数据更加紧凑,并释放不需要的空间,从而提高访问效率和空间效率。DM8 提供的重建索引的系统函数为:
SP_REBUILD_INDEX(SCHEMA_NAME varchar(256), INDEX_ID int);
SCHEAM_NAME 为索引所在的模式名,INDEX_ID 为索引 ID。
使用说明:
(1)水平分区子表,临时表和系统表上建的索引不支持重建
(2)虚索引和聚集索引不支持重建
例 需要重建索引 emp_name,假设其索引 ID 为 1547892,那么使用以下语句重建索引:
SP_REBUILD_INDEX('SYSDBA', 1547892);
用户可能出于以下某项原因需要删除一个索引:
(1)不再需要该索引;
(2)该索引没有为针对其相关的表所发布的查询提供所期望的性能改善。例如,表可能很小,或者尽管表中有许多行但只有很少的索引项;
(3)应用没有用该索引来查询数据。
要想删除索引,则该索引必须包含在用户的模式中或用户必须具有 DROP ANY INDEX 数据库权限。索引删除之后,该索引的段的所有簇都返回给包含它的表空间,并可用于表空间中的其他对象。
如何删除索引,取决于是否是用 CREATE INDEX 语句明确地创建该索引的,是则可以用 DROP INDEX 语句删除该索引。
例 下面的语句删除 emp_ename 索引
DROP INDEX emp_ename;
删除不存在的索引会报错。若指定 IF EXISTS 关键字,删除不存在的索引,不会报错,例如:
DROP INDEX IF EXISTS emp_ename;
然而,不能直接删除与已启用的 UNIQUE KEY 键或 PRIMARY KEY 键约束相关的索引。要删除一个与约束相关的索引,必须停用或删除该约束本身。
例 下面的语句删除主键约束 pk_emp_name,同时删除其对应的索引
ALTER TABLE emp DROP CONSTRAINT pk_emp_name;
除了删除普通索引,DM8 还提供删除聚集索引,只要其聚集索引是通过 CREATE CLUSTER INDEX 明确建立的。
例 下面的语句删除 emp 表的聚集索引 clu_emp_name
DROP INDEX clu_emp_name;
删除聚集索引其实是使用 ROWID 作为索引列重建聚集索引,即跟新建聚集索引一样会重建这个表以及其所有索引。
删除表就自动删除了所有与其相关的索引。
创建索引后,可以通过 INDEXDEF 系统函数查看索引的定义。
INDEXDEF(INDEX_ID int, PREFLAG int);
INDEX_ID 为索引 ID,PREFLAG 表示返回信息中是否增加模式名前缀。
例 需要查看索引 emp_name 的定义,假设其索引 ID 为 1547892,那么使用以下语句查看索引定义
SELECT INDEXDEF(1547892, 0);
或
SELECT INDEXDEF(1547892, 1);
社区地址:https://eco.dameng.com/
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。