IBM®
跳转到主要内容
    中国 [选择]    使用条款
 
 
Select a scope:Search for:    
    首页    产品    服务与解决方案     支持与下载    个性化服务    
跳转到主要内容

developerWorks 中国  >  Information Management  >

关于 DB2 通用数据库中索引覆盖的基本事实

developerWorks
文档选项

未显示需要 JavaScript 的文档选项


级别: 初级

Alexander Kuznetsov, Chicago,IL

2003 年 3 月 01 日

笔者 Alexander Kuznetsov 用一些示例展示了,向索引添加一列或两列来‘覆盖’SELECT 语句中的列,从而提高查询性能。DB2 优化器非常擅于识别这种情形,并且可以选择高效的执行计划。

本文专门针对 IBM® DB2® Universal Database® for Linux、UNIX® 和 Windows®。

简介

有时向索引添加一列或两列可以将查询性能提高十倍或更多。我将在本文中讨论这种情形:在一个或多个索引中可以找到执行 SELECT 查询所需的所有列;换句话说,一个索引(或多个索引) 覆盖了查询。在这种情况下,只涉及索引的执行计划可能是最有效的执行计划。

DB2 优化器非常擅于识别这种情形,它能够选择非常有效的、涉及 索引覆盖的执行计划。我将研究几个示例,在这些示例中,向索引添加一列或多列就能使查询的执行速度更快,这是因为:

  • 因为索引通常比表小,所以扫描索引通常所需的 I/O 较少。
  • 因为索引条目已经经过排序,所以不需要排序结果集就可以执行带相应 ORDER BY、GROUP BY 或 DISTINCT 子句的 SELECT 语句。
  • 因为索引条目已经经过排序,所以归并连接不需要任何排序。

另外,我将讨论如何让一个(同一个)索引覆盖几条查询,这有助于使索引数目尽可能的少。





回页首


本文所使用的模式

以下是本文示例将要用到的表:

CREATE TABLE CUSTOMER_DATA(
ID INT NOT NULL, 
FIRST_NAME VARCHAR(30), 
LAST_NAME VARCHAR(30), 
SALUTATION VARCHAR(10), 
ADDRESS VARCHAR(30), 
CITY VARCHAR(30), 
STATE CHAR(2), 
ZIP VARCHAR(10), 
PHONE_AREA SMALLINT, 
PHONE_NUMBER INTEGER, 
TOTAL_AMOUNT FLOAT, 
SOME_OTHER_DATA VARCHAR(100));
CREATE TABLE CUSTOMER_ORDER(
CUSTOMER_ID INT NOT NULL, 
ORDER_NUMBER SMALLINT NOT NULL, 
ORDER_DT DATE, 
AMOUNT FLOAT, 
SOME_OTHER_DATA VARCHAR(100))
ALTER TABLE CUSTOMER_DATA ADD PRIMARY KEY(ID)
ALTER TABLE CUSTOMER_ORDER ADD PRIMARY KEY(CUSTOMER_ID, ORDER_NUMBER)
ALTER TABLE CUSTOMER_ORDER ADD FOREIGN KEY(CUSTOMER_ID) 
	REFERENCES CUSTOMER_DATA(ID)
CREATE INDEX CUSTOMER_NAMES ON CUSTOMER_DATA(LAST_NAME, FIRST_NAME);

(注:DB2 会自动创建实现主键约束的索引。)

我们还将假定关于这两个表的统计信息是最新的、详细的并包括分布统计信息。本文中的所有示例均使用缺省优化等级 5。





回页首


好处:加速经常执行的查询

考虑下面这条非常简单且经常执行的查询:

SELECT SUM(AMOUNT) FROM CUSTOMER_ORDER WHERE CUSTOMER_ID = 1000

优化器选择通过关于 CUSTOMER_ID 的索引来访问表中的行。

让我们将这条查询保存在 sum_amt.sql 文件中,然后用 db2batch 来测量这条查询的实际执行成本,如下所示:

db2batch -d test2 -f sum_amt.sql -r perf_pk.txt -o p 3

(参考资料 [ 3] 中描述了 db2batch 命令的完整语法)。运行该命令之后,文件 perf_pk.txt 包含一个关于执行这条查询的成本的报告:

...
Buffer pool data logical reads               = 12
Buffer pool data physical reads              = 10
...
Buffer pool index logical reads              = 3
Buffer pool index physical reads             = 1

在这个特定情形下,索引深度为 3。根索引页和相关非叶子级页已经存在于缓冲池中,所以只有叶级索引页需要物理读取( index physical reads = 1 )。(注:叶子这一层的索引条目可以跨两个或更多叶子页。)在缓冲池内只有两个相关数据页,所以必须从磁盘读取其余的(10 个)数据页。对于 OLTP 活动,大多数索引页通常已经存在于缓冲池中。另外,在这种情况下,没有按该索引来群集表,所以与搜索条件相匹配的那 12 条记录分布在如 图 1所示的表中。


图 1. 使用表访问实现查询
使用表访问实现查询

如果该表按照关于 CUSTOMER_ID 的索引进行群集,则这条查询可以有更好的性能。关于群集索引的更多信息,请参阅参考资料 [ 2]。

现在,让我们创建索引来加速该查询:

CREATE INDEX ORDER_CUST_AMT ON CUSTOMER_ORDER(CUSTOMER_ID, AMOUNT);
RUNSTATS ON TABLE DB2INST1.CUSTOMER_ORDER WITH DISTRIBUTION AND DETAILED INDEXES ALL;

(关于 RUNSTATS 语法的更多信息,请参阅参考资料 [ 3])。注:因为在创建索引时,不会自动创建统计信息,所以必须显式地创建统计信息。这个新的索引包含了实现该查询所需的全部列。执行该查询时,优化器选择只访问这个索引,而根本不访问该表:


图 2. 使用纯索引访问实现查询
使用纯索引访问实现查询

正如 图 2所示,在这个特定情形下,添加第二列之后,索引深度没有增加。另外,在这种情况下,一个叶子页中包含了与搜索条件相匹配的索引条目。注:索引深度可能会增加,因为索引条目增加了。另外还要注意,与搜索条件相匹配的索引条目可能跨两个数据页。

现在,我们来讨论由 dynexpln 实用程序所生成的执行计划以及实际的执行成本:

dynexpln -d test2 -o output.txt -q "SELECT SUM(AMOUNT) FROM 
	CUSTOMER_ORDER WHERE CUSTOMER_ID = 1000"
...
|  |  Index-Only Access
(...)
Buffer pool data logical reads               = 0
Buffer pool data physical reads              = 0
(...)
Buffer pool index logical reads              = 3
Buffer pool index physical reads             = 1

(关于 dynexpln 的更多信息,请参阅参考资料 [ 2] 和 [ 1]。)

纯索引访问显示出执行这条查询的成本非常低。如果索引深度增加,同时索引条目跨两个页面,该查询需读取 5 次,这仍然比访问表的方式要好。

虽然这似乎是一个过于简单的示例,但它展示了索引覆盖的好处。正如我们所看到的,索引覆盖将执行查询时所需的 I/O 数目降到了最少,极大地提高了查询性能。另外,请记住,在这个特定情形下:

  • 平均至少有几条记录与搜索条件相匹配。
  • 因为没有在关于 CUSTOMER_ID 的索引上群集表,所以这些记录通常分布在表中的各个地方。
  • 实现这条查询不需要大多数的列。

在其它情形下, 索引覆盖的好处(如果有的话)不太明显。

我们刚才讨论了一个示例,在这个示例中,检索的记录数目非常少,并且这些记录分布在表中各个地方。另一个与此非常类似的示例是:

SELECT FIRST_NAME, LAST_NAME, PHONE_AREA, PHONE_NUMBER 
FROM CUSTOMER_DATA ORDER BY LAST_NAME FETCH FIRST 30 ROWS ONLY;

同样,只检索了少量的记录(至多 30 条)。如果有关于 FIRST_NAMELAST_NAMEPHONE_AREAPHONE_NUMBER 的索引,则它可以覆盖该查询。同样,如果这个索引的群集率很低,则该查询的性能将会极大地得到提高,原因与第一个示例中的一样。





回页首


好处:扫描索引而不扫描表

如果一个表很大,则扫描该表以满足查询所付出的成本可能很大。只要索引比其基表小(通常是这样),扫描索引就可能是一种成本较小的替代方案。

考虑下面这条简单查询:

SELECT LAST_NAME, FIRST_NAME FROM CUSTOMER_DATA WHERE LAST_NAME LIKE '%STONE'"

假定有一个关于 LAST_NAME 的索引,但关于 LAST_NAMEFIRST_NAME 的索引被删除了。注:谓词 LAST_NAME LIKE '%STONE' 是不可索引的。优化器选择了扫描表空间,通过查看 dynexpln 的输出就可以看出这一点。

dynexpln -d test2 -o likestone1.txt -q "SELECT LAST_NAME, 
FIRST_NAME FROM CUSTOMER_DATA WHERE LAST_NAME LIKE '%STONE'"
SQL Statement:
  
  SELECT LAST_NAME, FIRST_NAME 
  FROM CUSTOMER_DATA 
  WHERE LAST_NAME LIKE '%STONE'
        Estimated Cost        = 10381
Estimated Cardinality = 1383
Access Table Name = DB2INST1.CUSTOMER_DATA  ID = 2,5
|  #Columns = 1
|  
        Relation Scan
|  |  Prefetch: Eligible
|  Lock Intents
|  |  Table: Intent Share
|  |  Row  : Next Key Share
|  Sargable Predicate(s)
|  |  #Predicates = 1
|  Return Data to Application
|  |  #Columns = 2
Return Data Completion
      

当创建了关于 LAST_NAMEFIRST_NAME 的索引之后,优化器选择使用该索引:

db2 "CREATE INDEX DC_LN ON CUSTOMER_DATA(LAST_NAME, FIRST_NAME)"
db2 RUNSTATS ON TABLE DB2INST1.CUSTOMER_DATA WITH 
DISTRIBUTION AND DETAILED INDEXES ALL
dynexpln -d test2 -o likestone2.txt -q "SELECT LAST_NAME, 
FIRST_NAME FROM CUSTOMER_DATA WHERE LAST_NAME LIKE '%STONE'"
SQL Statement:
  
  SELECT LAST_NAME, FIRST_NAME 
  FROM CUSTOMER_DATA 
  WHERE LAST_NAME LIKE '%STONE'
        Estimated Cost        = 707
Estimated Cardinality = 1383
Access Table Name = DB2INST1.CUSTOMER_DATA  ID = 2,5
|  #Columns = 2
|  Index Scan:  Name = DB2INST1.DC_LN  ID = 2
|  |  Index Columns:
|  |  |  1: LAST_NAME (Ascending)
|  |  |  2: FIRST_NAME (Ascending)
|  |  #Key Columns = 0
|  |  |  Start Key: Beginning of Index
|  |  |  Stop Key: End of Index
|  |  
        Index-Only Access
|  |  Index Prefetch: Eligible 84
|  |  Sargable Index Predicate(s)
|  |  |  #Predicates = 1
|  |  |  Return Data to Application
|  |  |  |  #Columns = 2
|  Lock Intents
|  |  Table: Intent Share
|  |  Row  : Next Key Share
Return Data Completion
      

正如我们所看到的,仅仅因为索引小得多,索引扫描的估计成本就远远低于表空间扫描的成本了。如果频繁地使用索引,则很可能在缓冲池中找到索引页。如果是那种情况,则索引覆盖的实际执行成本要更小。





回页首


好处:消除对结果集进行排序的需要

每当查询语句中包含 ORDER BY、GROUP BYDISTINCT 子句,则执行该查询可能需要排序。排序可能会消耗大量资源。索引条目是已经经过排序的,因此索引覆盖可能消除对结果集进行排序的需要,从而提高查询的性能。例如,考虑带 ORDER BY 子句的查询:

 SELECT LAST_NAME, FIRST_NAME, PHONE_AREA, PHONE_NUMBER 
  	FROM CUSTOMER_DATA 
  	ORDER BY LAST_NAME, FIRST_NAME

虽然有关于 LAST_NAMEFIRST_NAME 的索引,但没有按该索引群集该表。在这种情况下,对表空间进行全扫描,然后排序结果集,这种方式有时比通过索引来访问表更有效。(在我以前的文章 当我们认为优化器没有正常工作时中,就类似问题做了简要讨论)。在这个特定情形下,这是优化器所做的选择:

SQL Statement:
  
  SELECT LAST_NAME, FIRST_NAME, PHONE_AREA, PHONE_NUMBER 
  FROM CUSTOMER_DATA 
  ORDER BY LAST_NAME, FIRST_NAME
        Estimated Cost        = 25736
Estimated Cardinality = 59616
Access Table Name = DB2INST1.CUSTOMER_DATA  ID = 2,5
|  #Columns = 4
|  
        Relation Scan
|  |  Prefetch: Eligible
|  Lock Intents
|  |  Table: Intent Share
|  |  Row  : Next Key Share
|  Insert Into Sorted Temp Table  ID = t1
|  |  #Columns = 4
|  |  
        #Sort Key Columns = 2
|  |  |  Key 1: LAST_NAME (Ascending)
|  |  |  Key 2: FIRST_NAME (Ascending)
|  |  
        Sortheap Allocation Parameters:
|  |  |  #Rows     = 59616
|  |  |  Row Width = 44
|  |  Piped
Sorted Temp Table Completion  ID = t1
Access Temp Table  ID = t1
|  #Columns = 4
|  Relation Scan
|  |  Prefetch: Eligible
|  Return Data to Application
|  |  #Columns = 4
Return Data Completion
      

对于该查询,对结果集排序耗尽了大多数资源,因为对于不带 ORDER BY 子句的同一条查询,估计的和实际的执行成本都至少降低 50%。用索引覆盖查询,SELECT 操作几乎会立即得出结果,因为:

  • 它需要读取较少的页面(索引比其表要小)
  • 它不必排序结果

让我们创建关于 LAST_NAMEFIRST_NAMEPHONE_AREAPHONE_NUMBER 的索引,并创建统计信息。现在执行计划使用索引覆盖:

SQL Statement:
  
  SELECT LAST_NAME, FIRST_NAME, PHONE_AREA, PHONE_NUMBER 
  FROM CUSTOMER_DATA 
  ORDER BY LAST_NAME, FIRST_NAME
        Estimated Cost        = 685
Estimated Cardinality = 59616
Access Table Name = DB2INST1.CUSTOMER_DATA  ID = 2,5
|  #Columns = 4
|  Index Scan:  Name = DB2INST1.CUST_DIRECTORY  ID = 4
|  |  Index Columns:
|  |  |  1: LAST_NAME (Ascending)
|  |  |  2: FIRST_NAME (Ascending)
|  |  |  3: PHONE_AREA (Ascending)
|  |  |  4: PHONE_NUMBER (Ascending)
|  |  #Key Columns = 0
|  |  |  Start Key: Beginning of Index
|  |  |  Stop Key: End of Index
|  |  
        Index-Only Access
|  |  Index Prefetch: Eligible 79
|  |  |  Return Data to Application
|  |  |  |  #Columns = 4
|  Lock Intents
|  |  Table: Intent Share
|  |  Row  : Next Key Share
Return Data Completion
      

类似的,索引覆盖提高了带 GROUP BYDISTINCT 子句的查询性能。例如,访问关于 LAST_NAMEFIRST_NAME 的索引实现了这两条查询,消除了在执行这两条查询期间排序的需要,所以提高了查询性能:

SELECT LAST_NAME, FIRST_NAME, COUNT(*) FROM CUSTOMER_DATA 
        GROUP BY LAST_NAME, FIRST_NAME;
SELECT 
        DISTINCT LAST_NAME, FIRST_NAME FROM CUSTOMER_DATA;
      

注:我们假定唯一索引的所有列都包含在该 SELECT 列表中。在这种情况下,任何结果集都是唯一的。即使没有索引覆盖,DB2 优化器也能够识别这种情况,并能消除不必要的排序。

正如我们所看到的, 索引覆盖可以极大地提高了带 ORDER BYGROUP BYDISTINCT 子句的 SELECT 查询的性能。





回页首


好处:加速父表和子表的连接

即使在一条查询中涉及多个表时,DB2 优化器也非常“聪明”,能够选择 索引覆盖。考虑下面这条简单的查询:

SELECT CUSTOMER_DATA.FIRST_NAME, CUSTOMER_DATA.LAST_NAME, 
	CUSTOMER_DATA.PHONE_AREA, CUSTOMER_DATA.PHONE_NUMBER, 
	CUSTOMER_ORDER.ORDER_NUMBER, CUSTOMER_ORDER.ORDER_DT, 
	CUSTOMER_ORDER.AMOUNT 
FROM CUSTOMER_DATA JOIN CUSTOMER_ORDER ON ID = CUSTOMER_ID

如果只存在那些用于实现主键和外键约束的索引,则执行查询的估计成本为:

        Estimated Cost        = 40421
Estimated Cardinality = 357696
      

让我们添加相应的索引(注:我们可能希望让这些索引实现主键和外键约束,我们将在后面讨论这些)。

CREATE INDEX DATA_IND ON CUSTOMER_DATA(ID, FIRST_NAME, 
LAST_NAME, PHONE_AREA, PHONE_NUMBER);
CREATE INDEX ORDER_IND ON CUSTOMER_ORDER(CUSTOMER_ID, 
ORDER_NUMBER, ORDER_DT, AMOUNT);

现在执行这条查询的速度更快。

        Estimated Cost        = 15404
Estimated Cardinality = 357696
Access Table Name = DB2INST1.CUSTOMER_DATA  ID = 2,5
|  #Columns = 5
|  Index Scan:  Name = DB2INST1.DATA_IND  ID = 3
|  |  Index Columns:
|  |  |  1: ID (Ascending)
|  |  |  2: FIRST_NAME (Ascending)
|  |  |  3: LAST_NAME (Ascending)
|  |  |  4: PHONE_AREA (Ascending)
|  |  |  5: PHONE_NUMBER (Ascending)
|  |  #Key Columns = 0
|  |  |  Start Key: Beginning of Index
|  |  |  Stop Key: End of Index
|  |  
        Index-Only Access
(snip)
Merge Join
|  Access Table Name = DB2INST1.CUSTOMER_ORDER  ID = 2,6
|  |  #Columns = 3
|  |  Index Scan:  Name = DB2INST1.ORDER_IND  ID = 1
|  |  |  Index Columns:
|  |  |  |  1: CUSTOMER_ID (Ascending)
|  |  |  |  2: ORDER_NUMBER (Ascending)
|  |  |  |  3: ORDER_DT (Ascending)
|  |  |  |  4: AMOUNT (Ascending)
|  |  |  #Key Columns = 0
|  |  |  |  Start Key: Beginning of Index
|  |  |  |  Stop Key: End of Index
|  |  |  
        Index-Only Access
      

在这种情况下,两个表都没有关于 CUSTOMER_ID 进行群集。如果父表和子表都针对 CUSTOMER_ID 进行群集,则 索引覆盖的好处可能不太明显,甚至毫无意义。

对于这条查询, 索引覆盖与不使用该方法的成本相比(15404 vs. 40421),其好处是相当明显的。正如我们所看到的,使用 索引覆盖来加速连接是很有意义的。





回页首


使用一个索引来覆盖几条查询

假定我们需要提高几个经常执行的查询的性能,譬如:

SELECT CUSTOMER_ID, SUM(AMOUNT) FROM CUSTOMER_ORDER GROUP 
BY CUSTOMER_ID;
SELECT CUSTOMER_ID, MIN(ORDER_DT) FROM CUSTOMER_ORDER GROUP 
BY CUSTOMER_ID;
SELECT SUM(AMOUNT) FROM CUSTOMER_ORDER;

当然,我们可以为每条需要优化的查询创建一个索引(或者实现的查询表):

CREATE INDEX CUST_ID_AMT ON CUSTOMER_ORDER(CUSTOMER_ID, 
AMOUNT) ALLOW REVERSE SCANS;
CREATE INDEX CUST_ID_ORDER_DT ON CUSTOMER_ORDER
(CUSTOMER_ID, ORDER_DT) ALLOW REVERSE SCANS;
CREATE INDEX CUST_AMOUNT ON CUSTOMER_ORDER(AMOUNT) ALLOW 
REVERSE SCANS;

然而,这些附加的索引会减慢对其基表所做的全部修改,并会耗尽磁盘空间。在许多情况下,需要在加速 SELECT 查询和减慢插入、更新和删除操作之间进行某些折衷。在这种情况下,让一个索引覆盖几条查询是非常有用的。例如,下面是一个覆盖上面所列出的所有查询的索引:

CREATE INDEX ORDER_COVERING ON CUSTOMER_ORDER(CUSTOMER_ID, 
ORDER_DT, AMOUNT) ALLOW REVERSE SCANS;
RUNSTATS ON TABLE DB2INST1.CUSTOMER_ORDER WITH DISTRIBUTION 
AND DETAILED INDEXES ALL;





回页首


用一个索引覆盖一条查询,并实现一条约束

这里还有另一项技术,用此技术可以使索引数目较少。在这个示例中,我将用一个索引来实现主键约束,并覆盖本文所用到的全部查询:

ALTER TABLE CUSTOMER_ORDER DROP PRIMARY KEY;
CREATE UNIQUE INDEX ORDER_PK 
	ON CUSTOMER_ORDER(CUSTOMER_ID, ORDER_NUMBER) 
	INCLUDE(ORDER_DT, AMOUNT) ALLOW REVERSE SCANS;
ALTER TABLE CUSTOMER_ORDER ADD PRIMARY KEY(CUSTOMER_ID, ORDER_NUMBER);
RUNSTATS ON TABLE DB2INST1.CUSTOMER_ORDER WITH DISTRIBUTION AND DETAILED INDEXES ALL;

在这个示例中,DB2 将发出一条警告,并重用已经存在的索引 ORDER_PK 以实现主键约束。

CREATE INDEX 语句中的 INCLUDE 子句意味着这个索引可以保证( CUSTOMER_ID, ORDER_NUMBER )对的唯一性,同时还包含 ORDER_DTAMOUNT 列。关于 CREATE INDEX 语法的详细信息,请参阅参考资料 [ 4]。

然而,应该适度地使用该技术。在许多情况下,让较小的索引来实现约束要更好一些。





回页首


用多个索引来覆盖一条查询

现在,让我们探讨一下优化器如何选择用两个索引来覆盖一条查询。让我们假定目前没有关于 FIRST_NAMELAST_NAME 的索引(我们在前面几节中用到了这个索引,但在这种情况下假定不存在该索引)。

DROP INDEX CUSTOMER_NAMES

下面是这两个索引和这条查询:

CREATE INDEX DATA_FIRST_NAME ON CUSTOMER_DATA(FIRST_NAME)
CREATE INDEX DATA_LAST_NAME ON CUSTOMER_DATA(LAST_NAME)
SELECT FIRST_NAME, LAST_NAME FROM CUSTOMER_DATA WHERE 
((FIRST_NAME LIKE 'RO%') AND (LAST_NAME LIKE 'TRA%'))

(如果有关于 FIRST_NAMELAST_NAME 的索引,则很可能就用它来实现该查询。我们现在正在考虑当不存在这样方便的索引时的情形。)在这个特定的情形下,优化器选择访问这两个索引,而不访问表本身:

|  |  Access Table Name = DB2INST1.CUSTOMER_DATA  ID = 2,5
|  |  |  #Columns = 1
|  |  |  Index Scan:  Name = DB2INST1.DATA_LAST_NAME  ID = 2
|  |  |  |  Index Columns:
|  |  |  |  |  1: LAST_NAME (Ascending)
|  |  |  |  #Key Columns = 1
|  |  |  |  |  Start Key: Inclusive Value
|  |  |  |  |  |  1: 'TRA                 ...'
|  |  |  |  |  Stop Key: Inclusive Value
|  |  |  |  |  |  1: 'TRAZZZZZZZZZZZZZZZZZ...'
|  |  |  |  
        Index-Only Access
|  |  |  |  Index Prefetch: None
(snip)
|  Index ANDing Bitmap Probe
|  |  Access Table Name = DB2INST1.CUSTOMER_DATA  ID = 2,5
|  |  |  #Columns = 1
|  |  |  Index Scan:  Name = DB2INST1.DATA_FIRST_NAME  ID = 1
|  |  |  |  Index Columns:
|  |  |  |  |  1: FIRST_NAME (Ascending)
|  |  |  |  #Key Columns = 1
|  |  |  |  |  Start Key: Inclusive Value
|  |  |  |  |  |  1: 'RO                  ...'
|  |  |  |  |  Stop Key: Inclusive Value
|  |  |  |  |  |  1: 'ROZZZZZZZZZZZZZZZZZZ...'
|  |  |  |  
        Index-Only Access
      

正如我们所看到的,在这个特定的情形下,我们受益于索引覆盖而不必创建另一个索引。DB2 优化器这次选择使用两个已有的索引。所以,当确定是否还要创建另一索引时,要斟酌一番。





回页首


结束语

正如我们所看到的, 索引覆盖可以显著地加速 SELECT 查询,这种情形有许多种。但因为向索引添加列会减慢对表的更改,还是最好在仔细分析了您所处的实际情况之后,再使用这种技术。





回页首


参考资料

笔者十分感谢其妻子 Anna Krylova 对他的鼓励。



关于作者

照片:Alexander Kuznetsov

在软件设计、开发和数据库管理方面, Alexander Kuznetsov 具有 15 年的经验。目前他从事的工作是改进运行在数个 TB 数据库环境下的应用程序的性能。Alexander 是 IBM 认证的高级技术专家(DB2 群集)和 IBM 认证的解决方案专家(数据库管理和应用程序开发)。可以通过 alkuzo@mindspring.com 和 comp.databases.ibm-db2 新闻组与他联系。




对本文的评价

太差! (1)
需提高 (2)
一般;尚可 (3)
好文章 (4)
真棒!(5)

建议?




回页首


IBM 公司保留在 developerWorks 网站上发表的内容的著作权。未经IBM公司或原始作者的书面明确许可,请勿转载。如果您希望转载,请通过 提交转载请求表单 联系我们的编辑团队。
    关于 IBM 隐私条约 联系 IBM 使用条款