理解 DB2 中的列组统计信息

改善访问计划中的基数估计值

使用 IBM DB2® for Linux®,UNIX®,and Windows® (DB2)中的列组统计信息,当多个等式本地谓词或等式连接谓词互相关联时,优化器可以确定一个更好的查询访问计划,并且改善查询性能。本文将介绍如何使用列组统计信息。

Samir Kapoor, DB2 UDB 高级支持分析师, EMC

Samir Kapoor 是一位 IBM 认证的 DB2 UDB 高级技术专家。Samir 目前在 DB2 UDB Advanced Support - Down system division(DSD)团队工作,他具有引擎领域的深入知识。



Vincent Corvinelli, 顾问软件开发人员, IBM

Vincent Corvinelli 是 IBM 加拿大 DB2 for Linux®, UNIX®, and Windows® (DB2) Optimizer 小组的一名顾问软件开发人员。他在诊断和解决客户问题方面有丰富的经验。



2007 年 7 月 16 日

简介

DB2 SQL 优化器(后文简称为优化器)可以估计每个备选访问计划的执行成本,并根据其估计结果选择一个最佳访问计划。一个访问计划可以指定用来解析一条 SQL 语句的操作次序。

为正确地确定每种访问计划的成本,DB2 优化器需要准确的基数估计值。基数估计是这样一种过程:在应用了谓词或执行了聚集之后,优化器使用统计信息确定部分查询结果的大小。对于访问计划的每个操作符,优化器将估计该操作符的基数输出。一个或更多谓词的应用可以减少输出流基数。

在计算谓词对于基数估计值的组合过滤效果时,通常会假设这些谓词彼此之间是独立的。然而,这些谓词可以在统计方面彼此关联。单独地处理它们通常会导致优化器低估基数值。而基数值的低估又会导致优化器选择一个次优的访问计划。

对于至少应用了至少两个本地等式谓词的 SQL 语句,优化器将考虑使用多列统计信息来检测统计关联,并更加准确地估计多个谓词组合的过滤效果。同样对于连接两个或更多表的 SQL 语句,以及在一对表间至少使用了两个等式连接谓词的连接,优化器也会使用多列统计信息。

一个本地等式谓词是一个应用于单个表的等式谓词,其描述如下所示:

COLUMN = literal

其中 literal 可以是以下任一内容:

  • 一个常量值;
  • 一个参数标记或一个主变量;
  • 一个专用寄存器(例如,CURRENT DATE)

一个等式连接谓词的描述如下所示,它用于表 1 和表 2 间的连接:

T1.COLUMN = T2.COLUMN

DB2 V8.2 使用下面的多列统计信息:

  • 索引 keycard 统计信息:FIRST2KEYCARD、FIRST3KEYCARD、FIRST4KEYCARD 和 FULLKEYCARD
  • 列组统计信息:列组基数值

这些统计信息描述了包含两个或更多列的列集中不同分组的数量。

在 DB2 V8.2 出现之前,只能使用索引 keycard 统计信息,并且要受下列条件约束:

  • 索引必须是完全限定的。如果键中的所有列都可以被等式谓词 引用(连接谓词或本地谓词,但不是两者的混合),那么这个索引就是完全限定的。
  • 对于连接谓词,索引也必须是惟一的。

在 DB2 V8.2 中,通过考虑到所有索引 keycard 统计信息而不要求索引完全限定,DB2 SQL 优化器进一步扩展了多列统计信息的使用。它还考虑到了用户收集的任何列组统计信息。本文讨论了优化器如何利用这些统计信息,以及用户如何识别要收集的列组统计信息。


多个本地等式谓词的统计相关性

DB2 SQL 优化器试图检测多个本地等式谓词间的统计相关性。

示例 1:假设有一个表 SHOW_LISTINGS,它包含如下列:

表 1. SHOW_LISTINGS 表的描述
列名描述
SHOW_ID表外键,包含关于各演出清单的信息
CHANNEL_ID表外键,包含关于播放演出的每个频道的信息
STATION_ID表外键,包含和频道相关的每个电视台的信息
CITY_ID表外键,包含关于上演该演出的每个城市的信息
DAY演出播放的日期
TIME演出播放的当天的时间
<other columns>描述了演出清单的其他属性

由于演出只在某个电视台的某个频道播出,在一天的特定时间内,这些列(SHOW_ID,CHANNEL_ID,STATION_ID 和 TIME)彼此之间不是互相独立的。DAY 列独立于 TIME 列,但是它不独立于所有演出清单的 SHOW_ID。

设想一条应用了以下谓词的 SQL 语句:

P1: SHOW_ID = ?
P2: CHANNEL_ID = ?
P3: STATION_ID = ?
P4: TIME = ?

如果存在这样一个索引,其中的键包含谓词 P1-P4 引用的所有列,或者键中的前四列包含所引用的列,优化器将使用 FIRST4KEYCARD 索引统计信息(如果收集了索引统计信息的话),来检测谓词 P1-P4 之间的统计相关性。在应用了这四个谓词之后,优化器将计算一个更准确的基数估计值。例如,下面的任何一个索引可以用来检测这四个谓词间的统计相关性:

IX1 ON SHOW_LISTINGS(SHOW_ID, CHANNEL_ID, STATION_ID, TIME)
IX2 ON SHOW_LISTINGS(SHOW_ID, CHANNEL_ID, STATION_ID, TIME, CITY_ID)
IX3 ON SHOW_LISTINGS(SHOW_ID, CHANNEL_ID, STATION_ID, TIME, DAY, CITY_ID)

优化器使用 IX1 的 FULLKEYCARD 和 FIRST4KEYCARD 统计信息来检测所有四个谓词的相关性。类似地,它也可以使用 IX2 和 IX3 的 FIRST4KEYCARD。

不能使用如下所示的索引:

IX4 ON SHOW_LISTINGS(CITY_ID, SHOW_ID, CHANNEL_ID, STATION_ID, TIME)

由于每个 keycard 统计信息都将包含 CITY_ID 列,因此该列上未定义本地等式谓词。

如果不存在具有所需键的索引,那么可以在 SHOW_ID、CHANNEL_ID、STATION_ID 和 TIME 上收集列组统计信息。优化器使用这些列组统计信息,运用与处理索引的 FIRST4KEYCARD 统计信息相同的方式检测这四个谓词间的统计相关性。

DB2 优化器同样也会考虑具有谓词子集的索引或者列组统计信息。例如,看下面所示的索引:

IX5 ON SHOW_LISTINGS(SHOW_ID, STATION_ID, CITY_ID, CHANNEL_ID)

该索引不能使用 FIRST2KEYCARD 来检测谓词 P1 和 P3 的统计相关性。尽管只是部分纠正了谓词 P1-P4 间的统计相关性,但已足以允许优化器选择一个优秀的查询执行计划。此外,尽管索引 IX5 中的完整键包含 CHANNEL_ID 列,仍然不能使用 FULLKEYCARD 统计信息来检测与 P2 的相关性,因为它包含的 CITY_ID 列没有在谓词中引用。


多个等式连接谓词的统计相关性

DB2 SQL 优化器同样尝试检测两个表中的多个等式连接谓词间的统计相关性。

示例 2:考虑示例 1 中描述的 SHOW_LISTINGS 表,另外,RATINGS 表包含如下列:

表 2. RATINGS 表的描述
列名描述
SHOW_ID表外键,包含关于各演出清单的信息
CHANNEL_ID表外键,包含关于播放演出的每个频道的信息
STATION_ID表外键,包含和频道相关的每个电视台的信息
CITY_ID表外键,包含关于上演该演出的每个城市的信息
DAY播放演出的日期
TIME播放演出的时间
RATING在一天的某个时间,在特定城市中,某个电视台频道的演出清单的收视率

RATINGS 表包含描述不同城市演出清单的收视率信息,用户可能需要查询 RATINGS 表和 SHOW_LISTINGS 表的连接以检索这两个表的属性。一个查询在该连接上应用的谓词集包含以下内容:

P1: SHOW_LISTINGS.SHOW_ID = RATINGS.SHOW_ID
P2: SHOW_LISTINGS.CHANNEL_ID = RATINGS.CHANNEL_ID
P3: SHOW_LISTINGS.STATION_ID = RATINGS.STATION_ID

P1-P3 这三个谓词可能不是互相独立的;优化器试图使用任何可用的多列统计信息来检测谓词之间的相关性。

优化器只能检测和说明每一对连接表上的多个连接谓词间的统计相关性。例如,如果一条 SQL 语句包含如下谓词:

P1: T1.A = T2.A
P2: T1.B = T2.B
P3: T1.C = T3.C

优化器只尝试检测 P1 和 P2 间的统计相关性,因为它们只应用于相同的两个表的连接,T1 和 T2。P3 应用于 T1 和 T2 的连接;那是一个不同的连接。如果添加了第四个谓词,例如:

P4: T1.D = T2.D

优化器将进一步尝试检测 P3 和 P4 间的统计相关性。

为了说明等式连接谓词间的统计相关性,优化器使用连接所涉及的两表之一的多列统计信息;这个表被视为连接的父表。因此只需要在连接的父表中收集列组统计信息。连接的另一个表被指定为子表。如果父表不能确定,那么优化器就不能使用多列统计信息来检测连接谓词间的统计相关性。

附录 B 提供了优化器如何确定两个连接表中的父表和子表的具体示例和描述。对连接中的父表进行标识,或者判断连接中是否有父表,这对于避免收集无用的列组统计信息是非常有用的。如果尚无合适的索引可用,那么在连接中的每个表上收集列组统计信息即可。


收集多列统计信息

优化器考虑使用所有可用的索引 keycard 统计信息。如果具有统计相关性的谓词所引用的列集中,索引 keycard 统计信息不可用,可以使用 RUNSTATS 命令收集列组统计信息。下面是从 DB2 V82 提取的语法。

注意:对于 DB2 9,请在 Info Center 的 DB2 9 文档中查看语法。.

>>-RUNSTATS--ON TABLE--table name--+-USE PROFILE-----+--->
				   '-| Statistics Options |-'
Statistics Options:

						   .-ALLOW WRITE ACCESS-.
|--+------------------------+--+----------------+--------->
'-| Table Object Options |-'  '-ALLOW READ ACCESS--'


Table Object Options:

|--+-FOR--| Index Clause |----------------------------+---|
'-+-----------------------+--+--------------------+-'
 '-| Column Stats Clause |-'  '-AND--| Index Clause |-'

Column Stats Clause:

|--+-ON--| Cols Clause |-------------------------+---------|
'-+------------------+--| Distribution Clause |-'
 '-ON--| Cols Clause |-'

On Cols Clause:

.-ON ALL COLUMNS---------------------------------------------.
|                                         .-,-------------.    |
|                                         V               |    |
|--+-ON--+----------------COLUMNS--(----Column Option-+--)-+--|
|     '-+-ALL-+--COLUMNS AND-'                                 |
|       '-KEY-'                                                |
'-ON KEY COLUMNS----------------------------------------------'

“ON COLUMNS” 子句允许您指定一个列的列表,为它们收集统计信息。如果您指定了一组列,则会收集该组中惟一值的数量。未列出的列的统计信息非常明确。您可以在 “on-cols-clause” 和 “on-dist-cols-clause” 中使用这个子句。

gh

注意:目前还不支持为一组列收集分布统计信息。

注意:如果启用了 automatic runstats 并使用 RUNSTATS 命令收集了列组统计信息,automatic runstats 将覆盖这些统计信息,并丢弃列组统计信息。

AUTO_RUNSTATS 数据库配置设置表明是否启用了 automatic runstats:

Automatic runstats (AUTO_RUNSTATS)=ON

如果设置为 “ON”,则启用 automatic runstats。

AUTO_RUNSTATS 默认情况下使用 “具有所有分布和示例的详细索引” 的 RUNSTATS 选项。

您可以使用统计信息配置文件来覆盖默认的 RUNSTATS 选项。您可以将希望收集的任意列组统计信息添加到此配置文件中,以避免 automatic runstats 覆盖它们。

统计信息配置文件” 提供了关于统计信息配置文件的详细资料。

对于数据库分区特性(database partitioning feature,DPF)环境,automatic runstats 总是在目录分区上收集统计信息。如果表不存在于这个目录节点上,将使用表驻留的节点组的第一个分区。

将使用 RUNSTATS 命令的 “ON COLUMNS” 选项收集列组统计信息。例如,使用 SHOW_LISTINGS 表收集 SHOW_LISTINGS.SHOW_ID、SHOW_LISTINGS.CHANNEL_ID 和 SHOW_LISTINGS.STATION_ID 中的列组统计信息,执行如下 RUNSTATS 命令:

RUNSTATS ON TABLE schema_name.SHOW_LISTINGS 
ON COLUMNS ((SHOW_ID, CHANNEL_ID, 
STATION_ID))

如果只在 DAY 列收集列统计信息以及收集 SHOW_ID、CHANNEL_ID、STATION_ID 和 TIME 列的列组统计信息,则执行以下的 RUNSTATS 命令:

RUNSTATS ON TABLE schema_name.SHOW_LISTINGS 
ON COLUMNS ((SHOW_ID, CHANNEL_ID, 
STATION_ID, TIME), DAY)

注意:列统计信息是在列组中列出的所有列上收集的。在上面的命令中,列统计信息同样是在每一个列中收集的(SHOW_ID、CHANNEL_ID、STATION_ID 和 TIME)。

为了收集所有列的统计信息以及在 SHOW_ID、CHANNEL_ID、STATION_ID 和 TIME 中收集列组统计信息,执行下面的 RUNSTATS 命令:

RUNSTATS ON TABLE schema_name.SHOW_LISTINGS ON ALL COLUMNS AND
 ON COLUMNS 	((SHOW_ID, CHANNEL_ID, STATION_ID, TIME))

要收集多个多列统计信息,可以提供一个组集。下面的 RUNSTATS 命令在组(SHOW_ID、CHANNEL_ID 和 STATION_ID)和组(SHOW_ID、CHANNEL_ID、STATION_ID 和 TIME)中收集多列统计信息,同样也在 DAY 列上收集了列统计信息:

RUNSTATS ON TABLE schema_name.SHOW_LISTINGS ON COLUMNS 
((SHOW_ID, CHANNEL_ID, STATION_ID), (SHOW_ID, CHANNEL_ID, 
STATION_ID, TIME), DAY)

注意:对于索引统计信息来说,将为索引键的前两个列、前三列和前四列收集多个多列统计信息,而一个列组基数统计信息是为指定的各列组收集的。


确定何时收集列组统计信息

确定何时收集列组统计信息以及要收集哪些列组统计信息是比较困难的。这一节将为您介绍一些方法,帮助您确定何时需要列组统计信息。

本节的示例使用了 SAMPLE 数据库,可以通过执行 “db2sampl” 创建,此数据库使用 db2level:

Informational tokens are "DB2 v8.1.1.120", "s060801", "U808888", and FixPak "13".

示例 3:本地等式谓词

创建了 SAMPLE 数据库后,并没有在表上收集统计信息。首先,需要在 EMPLOYEE 表中收集统计信息:

RUNSTATS ON TABLE SCHEMA_NAME.EMPLOYEE WITH DISTRIBUTION;

考虑 SAMPLE 数据库中 EMPLOYEE 表上的如下查询:

SELECT EMPNO, FIRSTNME, LASTNAME, WORKDEPT, SEX, JOB, SALARY
FROM EMPLOYEE
WHERE JOB='ANALYST';

该查询从 EMPLOYEE 表返回两条记录:

EMPNO  FIRSTNME     LASTNAME        WORKDEPT SEX JOB      SALARY     
------ ------------ --------------- -------- --- -------- -----------
000130 DOLORES      QUINTANA        C01      F   ANALYST     23800.00
000140 HEATHER      NICHOLLS        C01      F   ANALYST     28420.00

 2 record(s) selected.

看一下为此查询选择的查询执行计划。

为此,使用 EXPLAIN 工具,它要求 EXPLAIN 表存在。

  1. 为了创建 EXPLAIN 表,执行以下代码:
    db2 -tvf $DB2PATH/misc/EXPLAIN.DDL
  2. 创建了 EXPLAIN 表之后,像下面这样对查询进行 EXPLAIN 处理:
    SET CURRENT EXPLAIN MODE EXPLAIN;
    
    SELECT EMPNO, FIRSTNME, LASTNAME, WORKDEPT, SEX, JOB, SALARY
    FROM EMPLOYEE
    WHERE JOB='ANALYST';
    
    SET CURRENT EXPLAIN MODE NO;

    使用 db2exfmt 工具查看查询执行计划:
    db2exfmt -d <DBNAME> -1 -g -o <FILENAME>
  3. 使用您喜爱的文本编辑器,您应看到像下面这样的查询执行计划:
            2 
         TBSCAN 
         (   2) 
         30.8464 
            2 
           |
           32 
     TABLE: SKAPOOR 
        EMPLOYEE

    基数估计值 2 符合实际结果。

  4. 为这个查询添加几个冗余的等式谓词 :
    SELECT EMPNO, FIRSTNME, LASTNAME, WORKDEPT, SEX, JOB, SALARY
    FROM EMPLOYEE
    WHERE JOB='ANALYST' AND SEX='F' AND WORKDEPT='C01';

    此查询返回和上面相同的结果集。但是看一下 EXPLAIN 工具生成的查询执行计划,基数估计值并不符合实际结果:

        0.0761719 
         TBSCAN 
         (   2) 
         31.4115 
            2 
           |
           32 
     TABLE: SKAPOOR 
        EMPLOYEE

    DB2 优化器假设这三个谓词是彼此独立的,因为不存在相关的索引或列组统计信息。

  5. 在 JOB、WORKDEPT 和 SEX 列中收集列组统计信息。
    RUNSTATS ON TABLE <SCHEMA_NAME>.EMPLOYEE ON ALL COLUMNS 
    AND COLUMNS ((JOB, WORKDEPT, SEX)) WITH DISTRIBUTION;

    使用这三个列的列组统计信息,DB2 优化器计算出一个更准确的基数估计值:

         1.77778 
         TBSCAN 
         (   2) 
         31.4214 
            2 
           |
           32 
     TABLE: SKAPOOR 
        EMPLOYEE

    与单一谓词查询计算出的结果不同,所计算出的基数估计值并不是 2,这是因为列组统计信息是一个一致分布统计信息。

示例 4:等式连接谓词

这个示例集中关注表 ORG 和 STAFF 的连接。首先,需要在这两个表上收集统计信息。现在,已经收集好了基本的统计信息。

RUNSTATS ON TABLE <SCHEMA_NAME>.ORG;
RUNSTATS ON TABLE <SCHEMA_NAME>.STAFF;

下面的查询连接 ORG 和 STAFF 表:

SELECT STAFF.NAME, ORG.DEPTNUMB, ORG.DEPTNAME, STAFF.SALARY
FROM ORG, STAFF
WHERE ORG.MANAGER = STAFF.ID AND ORG.DEPTNUMB = STAFF.DEPT
ORDER BY ORG.DEPTNUMB;

这个查询返回 8 个记录:

NAME      DEPTNUMB DEPTNAME       SALARY   
--------- -------- -------------- ---------
Molinare        10 Head Office     22959.20
Hanes           15 New England     20659.80
Sanders         20 Mid Atlantic    18357.50
Marenghi        38 South Atlantic  17506.75
Plotz           42 Great Lakes     18352.80
Fraye           51 Plains          21150.00
Lea             66 Pacific         18555.50
Quill           84 Mountain        19818.00

  8 record(s) selected.
  1. 使用 EXPLAIN 工具查看查询执行计划:
                    1 
                 TBSCAN 
                 (   2) 
                 33.2225 
                    2 
                   |
                    1 
                 SORT   
                 (   3) 
                 33.151 
                    2 
                   |
                    1 
                 HSJOIN 
                 (   4) 
                 33.0248 
                    2 
              /-----+-----\
           35                8 
         TBSCAN           TBSCAN 
         (   5)           (   6) 
         17.2334          15.3736 
            1                1 
           |                |
           35                8 
     TABLE: SKAPOOR  TABLE: SKAPOOR 
          STAFF             ORG

    这个示例使用了收集列组统计信息的简单方法。附录 B 包含一些示例,对判定连接中的父表做了进一步的分析。

  2. 对 STAFF 表的 ID、DEPT 列和 ORG 表的 MANAGER、DEPTNUMB 列做了连接,所以要在这两组列中收集列组统计信息:
    RUNSTATS ON TABLE <SCHEMA_NAME>.STAFF ON ALL COLUMNS AND COLUMNS ((ID, DEPT));
    RUNSTATS ON TABLE <SCHEMA_NAME>.ORG ON ALL COLUMNS AND COLUMNS ((MANAGER, DEPTNUMB));

DB2 优化器使用收集到的列组统计信息正确地估计了基数:

               8
             TBSCAN 
             (   2) 
             33.5658 
                2 
               |
               8
             SORT   
             (   3) 
             33.4243 
                2 
               |
               8      
             HSJOIN 
             (   4) 
             33.0363 
                2 
          /-----+-----\
       35                8 
     TBSCAN           TBSCAN 
     (   5)           (   6) 
     17.2334          15.3736 
        1                1 
       |                |
       35                8 
 TABLE: SKAPOOR  TABLE: SKAPOOR 
      STAFF             ORG

示例 5:查看多列统计信息

优化器利用两种类型的多列统计信息:索引 keycard 统计信息和列组统计信息。这个示例提供了查看表中可用多列统计信息的步骤。

选项 1. 使用 db2look 工具

db2look 工具用来生成 DDL 语句,从而重新创建数据库中定义的对象。可以使用 -m 选项来显示为这些对象收集的统计信息。

  1. 在 ORG 表中收集列组统计信息和索引统计信息:
    CREATE INDEX IX1 ON ORG (DEPTNUMB, DEPTNAME, MANAGER);
    
    RUNSTATS ON TABLE <SCHEMA_NAME>.ORG ON ALL COLUMNS
             AND COLUMNS ((DEPTNUMB, DEPTNAME, MANAGER, DIVISION, LOCATION))
             WITH DISTRIBUTION AND INDEXES ALL;
  2. 使用 db2look 工具查看 ORG 表的统计信息:
    db2look -d sample -e -a -m -t ORG -o org.ddl

    注意:使用 -h 选项查看关于 DB2look 工具的信息。

  3. 在 org.ddl 文件中查看输出。它应该包含如下用于列组统计信息的 UPDATE 语句:
    UPDATE SYSSTAT.COLGROUPS SET colgroupcard = 8
            WHERE colgroupid IN (SELECT colgroupid
            FROM SYSCAT.COLGROUPCOLS
            WHERE tabschema = 'SKAPOOR ' AND tabname = 'ORG'
                  AND colname = 'DEPTNUMB' AND oridnal = 1)
            AND colgroupid IN (SELECT colgroupid
            FROM SYSCAT.COLGROUPCOLS
            WHERE tabschema = 'SKAPOOR ' AND tabname = 'ORG'
                  AND colname = 'DEPTNAME' AND oridnal = 2)
            AND colgroupid IN (SELECT colgroupid
            FROM SYSCAT.COLGROUPCOLS
            WHERE tabschema = 'SKAPOOR ' AND tabname = 'ORG'
                  AND colname = 'MANAGER' AND oridnal = 3)
            AND colgroupid IN (SELECT colgroupid
            FROM SYSCAT.COLGROUPCOLS
            WHERE tabschema = 'SKAPOOR ' AND tabname = 'ORG'
                  AND colname = 'DIVISION' AND oridnal = 4)
            AND colgroupid IN (SELECT colgroupid
            FROM SYSCAT.COLGROUPCOLS
            WHERE tabschema = 'SKAPOOR ' AND tabname = 'ORG'
                  AND colname = 'LOCATION' AND oridnal = 5)
            AND colgroupid NOT IN (SELECT colgroupid
            FROM SYSCAT.COLGROUPCOLS
            WHERE tabschema = 'SKAPOOR ' 
                  AND tabname = 'ORG' AND oridnal = 6) ;

    注意:在 V8 FixPak 13 中,列组统计信息添加到了 db2look 工具中。

    上面的 update 语句列出了 SYSCAT.COLGROUPCOLS 视图的所有列,以及来自 SYSSTAT.COLGROUPS 的相关多列统计信息,它表示列集中不同组的数量。在这个示例中,以上的语句描述了列集(DEPTNUMB、DEPTNAME、MANAGER、DIVISION 和 LOCATION)具有八个不同的组。

    org.ddl 文件也包含如下用于索引统计信息的语句:

    UPDATE SYSSTAT.INDEXES
    SET NLEAF=1,
        NLEVELS=1,
        FIRSTKEYCARD=8,
        FIRST2KEYCARD=8,
        FIRST3KEYCARD=8,
        FIRST4KEYCARD=-1,
        FULLKEYCARD=8,
        CLUSTERFACTOR=-1.000000,
        CLUSTERRATIO=100,
        SEQUENTIAL_PAGES=0,
        DENSITY=0,
        AVERAGE_SEQUENCE_GAP=0.000000,
        AVERAGE_SEQUENCE_FETCH_GAP=0.000000,
        AVERAGE_SEQUENCE_PAGES=0.000000,
        AVERAGE_SEQUENCE_FETCH_PAGES=0.000000,
        AVERAGE_RANDOM_PAGES=1.000000,
        AVERAGE_RANDOM_FETCH_PAGES=0.000000,
        NUMRIDS=8,
        NUMRIDS_DELETED=0,
        NUM_EMPTY_LEAFS=0
    WHERE INDNAME = 'IX1' AND INDSCHEMA = 'SKAPOOR'
          AND TABNAME = 'ORG' AND TABSCHEMA = 'SKAPOOR';

    以上的 update 语句描述了下列多列统计信息。FIRST2KEYCARD 统计信息描述了列(DEPTNUMB,DEPTNAME)中不同组的数量,FIRST3KEYCARD 和 FULLKEYCARD 描述了完整列集(DEPTNUMB,DEPTNAME,MANAGER)中不同组的数量。FIRST4KEYCARD 的值为 -1,这是因为索引在该键中只有 3 列。

选项 2. 查询目录表

可以从 DB2 目录表中查询与 DB2look 工具输出中所描述的相同的信息。

  1. 如果尚未创建索引,请按选项 1 中的步骤 1 创建索引,在多个表中收集多个列组统计信息:
    RUNSTATS ON TABLE <SCHEMA_NAME>.ORG ON ALL COLUMNS
    AND COLUMNS ((DEPTNUMB, DEPTNAME, MANAGER, DIVISION, LOCATION), 
    (DEPTNUMB, DEPTNAME), (MANAGER, DIVISION)) 
    WITH DISTRIBUTION AND INDEXES ALL;
    
    RUNSTATS ON TABLE <SCHEMA_NAME>.EMPLOYEE ON ALL COLUMNS 
    AND COLUMNS ((EMPNO, WORKDEPT), (EMPNO, WORKDEPT, JOB));
  2. 查询目录表来检索列组统计信息。注意下面的查询是一个递归 SQL 语句,它会导致一个可以忽略的 SQL0347W 警告。可以使用 “UPDATE COMMAND OPTIONS USING W OFF” 选项阻止该警告出现。
    WITH TMP(ID, NUM) AS
    (
       SELECT COLGROUPID, MAX(ORIDNAL)
         FROM SYSCAT.COLGROUPCOLS
       GROUP BY COLGROUPID
    ),
    TMP2 (ID, NAME, NUM, TNAME, TSCHEMA) AS
    (
       SELECT ID, CAST(RTRIM(COLNAME) AS CHAR(128)), NUM, TABNAME, TABSCHEMA
         FROM TMP Y, SYSCAT.COLGROUPCOLS X
        WHERE X.COLGROUPID = Y.ID
          AND Y.NUM = X.ORIDNAL
      UNION ALL
       SELECT Y.ID, CAST(RTRIM(X.COLNAME) || ',' || Y.NAME AS CHAR(128)), Y.NUM-1,
       	 TNAME, TSCHEMA
         FROM TMP2 Y, SYSCAT.COLGROUPCOLS X
        WHERE Y.ID=X.COLGROUPID
          AND X.ORIDNAL=Y.NUM-1
          AND Y.NUM > 1
          AND TNAME = TABNAME
          AND TSCHEMA = TABSCHEMA
    )
    SELECT SUBSTR(TSCHEMA,1,10) TABSCHEMA, SUBSTR(TNAME,1,10) TABNAME, 
    	NAME COLS, COLGROUPCARD 
    FROM TMP2, SYSSTAT.COLGROUPS
    WHERE ID = COLGROUPID
    AND NUM = 1
    ORDER BY TABSCHEMA, TABNAME
    ;

    上面的查询返回如下记录:

    注意:TABSCHEMA 列中的值将是不同的。同样,COLS 结果列并强制转换为 CHAR(128),如果结果超过 128 个字符,它会将结果截断。在这个例子中,可能需要将 CAST 修改为一个更大的字符串。

    TABSCHEMA  TABNAME    COLS                                   COLGROUPCARD        
    ---------- ---------- ------------------------------//------ -----------------
    SKAPOOR    EMPLOYEE   EMPNO,WORKDEPT                                        32
    SKAPOOR    EMPLOYEE   EMPNO,WORKDEPT,JOB                                    32
    SKAPOOR    ORG        DEPTNUMB,DEPTNAME                                      8
    SKAPOOR    ORG        MANAGER,DIVISION                                       8
    SKAPOOR    ORG        DEPTNUMB,DEPTNAME,MANAGER,DIVISION,LOCATION            8
    
      5 record(s) selected with 1 warning messages suppressed.

    这些记录描述了 EMPLOYEE 表的两列组统计信息和 ORG 表的三列组统计信息。

    注意:在上面的查询中,注意 SYSCAT.SYSCOLGROUPCOLS 视图中的名为 “ORIDNAL” 的列。在 DB2 9 中,其拼写改为了 “ORDINAL”,所以,这个查询需要按照在 DB2 9 中使用的方法更新,如下所示:

    WITH TMP(ID, NUM) AS
    (
       SELECT COLGROUPID, MAX(ORDINAL)
         FROM SYSCAT.COLGROUPCOLS
       GROUP BY COLGROUPID
    ),
    TMP2 (ID, NAME, NUM, TNAME, TSCHEMA) AS
    (
       SELECT ID, CAST(RTRIM(COLNAME) AS CHAR(128)), NUM, TABNAME, TABSCHEMA
         FROM TMP Y, SYSCAT.COLGROUPCOLS X
        WHERE X.COLGROUPID = Y.ID
          AND Y.NUM = X.ORDINAL
      UNION ALL
       SELECT Y.ID, CAST(RTRIM(X.COLNAME) || ',' || Y.NAME AS CHAR(128)), Y.NUM-1,
       	 TNAME, TSCHEMA
         FROM TMP2 Y, SYSCAT.COLGROUPCOLS X
        WHERE Y.ID=X.COLGROUPID
          AND X.ORDINAL=Y.NUM-1
          AND Y.NUM > 1
          AND TNAME = TABNAME
          AND TSCHEMA = TABSCHEMA
    )
    SELECT SUBSTR(TSCHEMA,1,10) TABSCHEMA, SUBSTR(TNAME,1,10) TABNAME, NAME COLS,
    	 COLGROUPCARD 
    FROM TMP2, SYSSTAT.COLGROUPS
    WHERE ID = COLGROUPID
    AND NUM = 1
    ORDER BY TABSCHEMA, TABNAME
    ;
  3. 查询目录表以检索索引统计信息。

    注意:在 TABSCHEMA='SKAPOOR' 谓词中使用合适的模式名替换所提供的值。

    SELECT SUBSTR(COLNAMES, 1, 30) AS COLS, FIRST2KEYCARD, FIRST3KEYCARD,
    	 FIRST4KEYCARD, FULLKEYCARD
    FROM SYSSTAT.INDEXES
    WHERE TABSCHEMA='SKAPOOR' AND TABNAME='ORG';

    上述查询返回如下记录:

    COLS                       FIRST2KEYCARD FIRST3KEYCARD FIRST4KEYCARD FULLKEYCARD
    -------------------------- ------------- ------------- ------------- -----------
    +DEPTNUMB+DEPTNAME+MANAGER             8             8            -1           8
    
      1 record(s) selected.

    FIRST2KEYCARD 统计信息描述了在列(DEPTNUMB 和 DEPTNAME)中不同组的数量,FIRST3KEYCARD 和 FULLKEYCARD 描述了完整列集(DEPTNUMB,DEPTNAME 和 MANAGER)中不同组的数量。FIRST4KEYCARD 值为 -1,这是因为索引在键中只包含三列。


练习

在示例 3 和 4 中,优化器使用了索引统计信息,而没有使用列组统计信息,通过说明统计信息相关性来修正基数估计值。

尝试以下步骤:

  1. 创建如下索引:
    IXEMP_1 ON EMPLOYEE(JOB, WORKDEPT, SEX);
    IXSTAFF_1 ON STAFF(ID, DEPT);
    IXORG_1 ON ORG(MANAGER, DEPTNUMB);
  2. 对这些索引收集统计信息,但不收集任何列组统计信息:
    RUNSTATS ON TABLE <SCHEMA_NAME>.EMPLOYEE AND INDEXES ALL;
    RUNSTATS ON TABLE <SCHEMA_NAME>.STAFF AND DETAILED INDEXES ALL;
    RUNSTATS ON TABLE <SCHEMA_NAME>.ORG AND INDEXES ALL;
  3. 对示例 3 和 4 中的查询进行 EXPLAIN 处理。所得到的基数估计值符合上面的查询执行计划;然而,由于可用索引的不同,实际的计划会有所不同。注意收集的 DETAILED 统计信息并不影响基数估计值。
  4. 丢弃步骤 1 中创建的 IXEMP_1 和 IXSTAFF_1 索引,创建两个新的索引:
    IXEMP_1 ON EMPLOYEE(JOB, WORKDEPT, SEX, EMPNO);
    IXSTAFF_1 ON STAFF(ID, DEPT,NAME,JOB);
  5. 重复步骤 2 和步骤 3。其最后的基数估计值是相同的。

附录 A. 自动统计信息分析

RUNSTATS 实用程序提供了一个选项,用它可以注册和使用一个统计信息配置文件。DB2 的自动统计信息分析特性可以自动地生成统计信息配置文件。启用了这个特性后,将会收集有关数据库活动的信息并将其存储在查询反馈仓库中。在这些数据的基础之上,生成一个统计信息配置文件。该特性还会推荐对本地等式谓词使用两列组统计信息。这在测试环境中是一种游泳的工具,可标识有用的列组统计信息。

Info Center 中包含关于使用 自动统计信息分析 的更详细信息。.

注意:统计信息配置文件的自动生成只在 DB2 串行模式中是激活的,在联邦查询、DPF 环境之中以及使用分区内并行性时,该特性是被禁止的。


附录 B. 确定两个连接表中的父表

多个等式谓词的统计相关性 一节中讨论了一种简单方法,通过说明等式连接谓词间的统计相关性而收集多列统计信息,这一节将介绍优化器如何确定两个连接表中的父表(如果有的话)。鉴别优化器是否会检测一个父表,如果会的话,哪一个是父表,这对于了解何时进行列组统计信息的收集才是有效的以及在哪个表上收集是非常有用的。

优化器在一组连接两表的谓词中标识父表,这个表至少是一个连接谓词的父表,而且不是任何其他连接谓词的子表。一个连接谓词的父表被确定为在谓词列中具有较多不同值的表。例如,在 SHOW_LISTINGS.SHOW_ID = RATINGS.SHOW_ID 连接谓词中,如果 SHOW_LISTINGS.SHOW_ID 的 COLCARD 统计信息比 RATINGS.SHOW_ID 的 COLCARD 统计信息多,那么 SHOW_LISTINGS 就是这个连接谓词的父表,RATINGS 则是子表。

此外,优化器还尝试使用范围统计信息(HIGH2KEY 和 LOW2KEY)来验证父表,方法是确保子表中的值集是父表的子集。例如,在连接谓词 SHOW_LISTINGS.SHOW_ID = RATINGS.SHOW_ID 中,如果符合以下条件:

  • SHOW_LISTINGS.SHOW_ID 的 COLCARD 统计信息多于 RATINGS.SHOW_ID 的统计信息,并且
  • SHOW_LISTINGS.SHOW_ID 的 HIGH2KEY 多于或等于 RATINGS.SHOW_ID 的 HIGH2KEY,并且
  • RATINGS.SHOW_ID 的 LOW2KEY 少于或等于 RATINGS.SHOW_ID 的 LOW2KEY

那么 SHOW_LISTINGS 是这个连接谓词的父表,而 RATINGS 则是子表。

示例 B.1

假设以下一组谓词:

P1: SHOW_LISTINGS.SHOW_ID = RATINGS.SHOW_ID
P2: SHOW_LISTINGS.CHANNEL_ID = RATINGS.CHANNEL_ID
P3: SHOW_LISTINGS.STATION_ID = RATINGS.STATION_ID

在 P1 中,假设 COLCARD(SHOW_LISTINGS.SHOW_ID) > COLCARD(RATINGS.SHOW_ID)。

在 P2 中,假设 COLCARD(SHOW_LISTINGS.CHANNEL _ID) > COLCARD(RATINGS.CHANNEL_ID)。

在 P3 中,假设 COLCARD(SHOW_LISTINGS.STATION_ID) > COLCARD(RATINGS.STATION_ID)。

优化器将 SHOW_LISTINGS 表标识为所有三个谓词的父表,所以它同样将 SHOW_LISTINGS 标识为连接的父表。因此优化器使用 SHOW_LISTINGS 表中的列(SHOW_ID,CHANNEL_ID 和 STATION_ID)上可用的多列统计信息。

示例 B.2

使用示例 B.1 中的谓词:

在 P1 中,假设 COLCARD(SHOW_LISTINGS.SHOW_ID) > COLCARD(RATINGS.SHOW_ID)。

在 P2 中,假设 COLCARD(SHOW_LISTINGS.CHANNEL _ID) > COLCARD(RATINGS.CHANNEL_ID)。

在 P3 中,假设 COLCARD(SHOW_LISTINGS.STATION_ID) = COLCARD(RATINGS.STATION_ID)。

优化器在谓词 P1 和 P2 中将 SHOW_LISTINGS 表标识为父表,在谓词 P3 中既不是子表,也不是父表。所以优化器也将 SHOW_LISTINGS 标识为连接的父表。因此,优化器使用 SHOW_LISTINGS 表中的列(SHOW_ID,CHANNEL_ID 和 STATION_ID)上可用的多列统计信息。

示例 B.3

使用示例 B.1 中的谓词:

在 P1 中,假设 COLCARD(SHOW_LISTINGS.SHOW_ID) > COLCARD(RATINGS.SHOW_ID)。

在 P2 中,假设 COLCARD(SHOW_LISTINGS.CHANNEL _ID) < COLCARD(RATINGS.CHANNEL_ID)。

在 P3 中,假设 COLCARD(SHOW_LISTINGS.STATION_ID) = COLCARD(RATINGS.STATION_ID)。

优化器在谓词 P1 中将 SHOW_LISTINGS 表标识为父表,在谓词 P2 中将其标识为子表,在谓词 P3 中既不是子表也不是父表。所以,并不将 SHOW_LISTINGS 标识为连接中的父表(也不将 RATINGS 标识为连接的父表)。因此,优化器并不会检测这三个连接的谓词间的统计相关性。

数据库分区特性

在一个 DPF 环境中,如果表跨多个数据库分区而被分区,在下列条件满足的情况下,只能使用范围统计信息:

  1. 两个表在相同的列中被分区
  2. 表是并置的,就是说,它们处于同一节点组
  3. 连接谓词引用所有的分区键列
  4. 在相同的节点收集统计信息

如果不能够使用范围统计信息,那么优化器只能使用 COLCARD 统计信息来确定连接中的父表。在 DPF 环境中,在单个节点中收集统计信息将会导致在 COLCARD 统计信息出现错误。因此,确定父表时,优化器允许 COLCARD 统计信息中存在一些偏差(1%)。然而,这种偏差是以多列统计信息为基础的,因此如果该连接不是中立 的,并且连接中没有很明显的父表,那么在 DPF 中应该使用收集列组统计信息的简单方法。

示例 B.4

1. 确定两个表是否在相同列上被分区

除非两个表的数据分布相同,否则不能使用范围统计信息(HIGH2KEY 和 LOW2KEY)。因此,如果表不是在相同列被分区,优化器将无法推断出数据在两个表中的分布相同。

假设有两个表,T1 和 T2。T1 在多个数据库分区中被分区,在列(C1 和 C2)中具有分区键。同样,T2 也进行了分区,其分区键在列(C2 和 C3)中。

例 1.1 使用下列谓词连接 T1 和 T2:

P1:  T1.C1=T2.C2
P2:  T1.C2=T2.C3

这两个表被认为是在相同的列进行了分区,因为连接谓词按照与其各自的分区键相同的次序应用于列中。

例 1.2 使用下列谓词:

P1:  T1.C1=T2.C3
P2:  T1.C2=T2.C2

谓词没有按照与其各自的分区键相同的次序应用于列中,所以这两个表被认为不是在相同列上分区的。

例 1.3 使用下列谓词:

P1: T1.C1=T2.C1
P2: T1.C2=T2.C2
P3: T1.C3=T2.C3

这些表被认为不是在相同列分区的。

例 1.4 来看一下和示例 1.3 使用相同谓词的情形,但是假设 T2 是在列(C1,C2 和 C3)中分区的。

尽管表 T1 是在相同列分区的(T2 分区键的两个主要列),由于 T2 在 C3 中进一步分区,与只在(C1 和 C2)中分区相比,这将导致数据分布不同。因此,这两个表被认为是在不同列进行分区的。

2. 确定这两个表是否是并置的

假设有两个表,T1 和 T2,T1 属于节点组 N0 而 T2 属于节点组 N1,其中 N0 包含分区数 0 和 1 ,N1 包含分区数 1 和 2 。由于这两个表不在同一个节点组,将认为它们不是并置的。

3. 确定连接的谓词是否引用所有的分区键列

假设有两个表,T1 和 T2。T1 在多个数据库分区中被分区,分区键在列(C1 和 C2)。同样,T2 也被分区,分区键在列(C2 和 C3)。

3.1 使用这些谓词来连接 T1 和 T2:

P1:  T1.C1=T2.C2
P2:  T1.C2=T2.C3

这两个谓词都包含了所有的分区键列。

例 3.2 如果在示例 3.1 谓词中添加第三个谓词 P3,T1.C3=T2.C1,那么这三个谓词合起来仍然包含两个表中的所有分区键列。然而,如果仅使用 P1 和 P3,所有这三个谓词并不包含分区键列。

例 3.3如果在示例 3.1 谓词中添加第三个谓词 P3,T1.C3=T2.C3,那么这三个谓词合起来仍然包含两个表中的所有分区键列。然而,如果只使用P1 和 P3,那么只包含了 T2 的分区键列而没有包含 T1 的,所以条件并不符合。

完全限定的惟一索引

如果在上述条件的基础上,没有一个表被指定为连接的父表,优化器将进一步检查一个完全限定的惟一索引。如果连接谓词完全限定一个惟一索引,优化器使用惟一索引的 FULLKEYCARD 统计信息来检测和说明相等连接谓词之间的统计相关性。

中立连接

如果未在两个表间的任一等式连接谓词中标识出父表,优化器将把这个连接标识为中立(neutral)。如果两个列的 COLCARD 相同,并且它们包含的值的范围也是相同的(HIGH2KEY 和 LOW2KEY 统计信息是等同的),则不对这个等式连接谓词标识父表。

在 DB2 V8 的 FixPaks 13 及更早版本中,如果是一个中立的 NPK 连接,优化器就不会为两个表的连接说明一组等式连接谓词间的统计相关性。在 V8 FixPak 14 和 DB2 9 中,优化器的统计相关性检测得到了扩展,可以对中立的 NPK 连接进行统计相关性说明。

两个表引用相同的基表,这种自连接是中立连接的特例。在 V8.2 中,优化器开始为这种特例说明统计相关性。

示例 B.5:在父表中收集列组统计信息

这个例子主要关注表 ORG 和 STAFF 间的连接。首先,需要为表收集统计信息。现在,已经收集了基本的统计信息:

RUNSTATS ON TABLE <SCHEMA_NAME>.ORG;
RUNSTATS ON TABLE <SCHEMA_NAME>.STAFF;

假设如下查询连接表 ORG 和 STAFF:

SELECT STAFF.NAME, ORG.DEPTNUMB, ORG.DEPTNAME, STAFF.SALARY
FROM ORG, STAFF
WHERE ORG.MANAGER = STAFF.ID AND ORG.DEPTNUMB = STAFF.DEPT
ORDER BY ORG.DEPTNUMB;

这个查询返回 8 个记录:

NAME      DEPTNUMB DEPTNAME       SALARY   
--------- -------- -------------- ---------
Molinare        10 Head Office     22959.20
Hanes           15 New England     20659.80
Sanders         20 Mid Atlantic    18357.50
Marenghi        38 South Atlantic  17506.75
Plotz           42 Great Lakes     18352.80
Fraye           51 Plains          21150.00
Lea             66 Pacific         18555.50
Quill           84 Mountain        19818.00

 8 record(s) selected.

1. 使用 EXPLAIN 工具,查看查询执行计划:

                1 
             TBSCAN 
             (   2) 
             33.2225 
                2 
               |
                1 
             SORT   
             (   3) 
             33.151 
                2 
               |
                1 
             HSJOIN 
             (   4) 
             33.0248 
                2 
          /-----+-----\
       35                8 
     TBSCAN           TBSCAN 
     (   5)           (   6) 
     17.2334          15.3736 
        1                1 
       |                |
       35                8 
 TABLE: SKAPOOR  TABLE: SKAPOOR 
      STAFF             ORG

2. 查看连接谓词引用的列的列统计信息。如下查询为两个连接谓词中引用的表 ORG 和 STAFF 中的列从 DB2 目录表中检索有趣的列统计信息:

SELECT SUBSTR(COLNAME,1,20) AS COLNAME, COLCARD,
       SUBSTR(HIGH2KEY,1,10) AS HIGH2KEY,
       SUBSTR(LOW2KEY,1,10) AS LOW2KEY
FROM SYSSTAT.COLUMNS
WHERE TABNAME IN ('ORG', 'STAFF')
AND COLNAME IN ('MANAGER', 'DEPTNUMB', 'ID', 'DEPT')
ORDER BY TABNAME, COLNAME;
表 B.5 列统计信息
COLNAMECOLCARDHIGH2KEYLOW2KEY
DEPTNUMB86615
MANAGER827030
DEPT86615
ID3534020

3. 计算基数估计值。

等式连接谓词的过滤因子的估计值计算如下:

1/max(colcard_LHS,colcard_RHS).

其中 LHS 在连接谓词的左边,RHS 在连接谓词的右边。本例中有以下两个连接谓词:

P1: org.manager=staff.id
P2: org.deptnumb=staff.dept

以及过滤因子(ff),P1 和 P2 计算如下:

ff(P1) = 1 / max (8,35) = 1/35 = 0.0285714
ff(P2) = 1/max(8,8) = 1/8 = 0.125

使用过滤因子以及两个表的基数估计值,连接基数计算如下:

JoinCard  = Cardinality(ORG) * cardinality(STAFF) * ff(P1) * ff(P2)
          = 35 * 8 * 0.0285714 * 0.125
          = 1

4. 在连接中标识父表。

在表 B.5 中,列统计信息显示 STAFF 是连接的父表,因为符合以下条件:

对于谓词 org.manager=staff.id:

colcard(MANAGER)  < colcard(ID)
high2key(MANAGER) < high2key(ID)
low2key(MANAGER) > low2key(ID)

因此,这个谓词的父表是 STAFF。

对于谓词 org.deptnumb=staff.dept,colcard、high2key 和 low2key 统计信息是等同的。因此,这个谓词不存在父表,它应被视为“中立”。

5. 在父表中收集列组统计信息。

在步骤 4 中,STAFF 被标识为连接的父表,ORG 被标识为连接的子表,所以应在 STAFF 表的列(ID,DEPT)中收集列组统计信息:

RUNSTATS ON TABLE <SCHEMA_NAME>.STAFF ON ALL COLUMNS AND COLUMNS ((ID,DEPT));

使用这两个列的列组统计信息,DB2 优化器就可以准确地估计出基数:

               8  
             TBSCAN 
             (   2) 
             33.5658 
               2 
               |
               8
              SORT   
             (   3) 
             33.4243 
               2 
               |
               8
             HSJOIN 
             (   4) 
             33.0363 
                2 
          /-----+-----\
       35                8 
     TBSCAN           TBSCAN 
     (   5)           (   6) 
     17.2334          15.3736 
        1                1 
       |                |
       35                8 
 TABLE: SKAPOOR  TABLE: SKAPOOR 
      STAFF             ORG

示例 B.6 中立连接

考虑 T1 和 T2 这两个表的连接,使用以下谓词:

P1: T1.C1 = T2.C1
P2: T1.C2 = T2.C2
P3: T1.C3 = T2.C3

假设这两个表具有以下的统计信息:

表 B.6 中立连接统计信息
TABLENAMECOLNAMECOLCARDHIGH2KEYLOW2KEYTABLENAMECOLNAMECOLCARDHIGH2KEYLOW2KEY
T1C1100992T2C1100992
T1C21019991900T2C21019991900
T1C35'Y''B'T2C35'Y''B'

所有的谓词被看作是中立的,这是由于两个表的 stats 是相等的。因此,在 V8 FixPak 14 和 DB2 9 中,应该在任一个表(不要求两个表)的列(C1、C2 和 C3)中收集列组统计信息,这样,优化器就可以检测这些连接谓词的统计相关性。

示例 B.7

使用和示例 B.6 相同的谓词,假设表具有如下统计信息:

表 B.7 确定父表
TABLENAMECOLNAMECOLCARDHIGH2KEYLOW2KEYTABLENAMECOLNAMECOLCARDHIGH2KEYLOW2KEY
T1C1100992T2C110992
T1C21019991900T2C21019991900
T1C35'Y''B'T2C35'Y''B'

在这个场景中,谓词 P2 和 P3 看作是中立的,这是由于两个表的列 C2 和 C3 的统计信息是等同的。然而,C1 的统计信息显示 T1 是 P1 的父表,这是因为 T1.C1 的 COLCARD 比 T2.C1 的 COLCARD 大,并且两个列具有等同的 HIGH2KEY 和 LOW2KEYare 统计信息。因此,应该在 T1 的列(C1、C2 和 C3)中收集列组统计信息,这样,优化器就可以检测连接谓词间的统计相关性。

示例 B.8

使用和示例 B.6 相同的谓词,假设表具有下列统计信息:

表 B.8 统计信息
TABLENAMECOLNAMECOLCARDHIGH2KEYLOW2KEYTABLENAMECOLNAMECOLCARDHIGH2KEYLOW2KEY
T1C1100992T2C1109992
T1C21019991900T2C21019991900
T1C35'Y''B'T2C35'Y''B'

在这个场景中,谓词 P2 和 P3 被表示为中立的,这是由于两个表的 C2 和 C3 列的统计信息是等同的。然而,C1 的统计信息表明 T1 和 T2 都不是父表,它也不是中立的,因为 T1.C1 具有一个更高的 COLCARD 统计信息,而 T2.C1 具有一个更高的统计信息。因此,应该在 T1 或 T2 的列(C2 和 C3)中收集列组统计信息,这样优化器就可以检测连接谓词 P2 和 P3 之间的统计相关性。

示例 B.9 使用 DPF 和范围统计信息

考虑 T1 和 T2 这两个表的连接,它们在多个数据库分区上被分区,并且是并置的,统计信息是在相同的节点手机的,分区键在列(C1 和 C2)上,使用如下谓词进行连接:

P1: T1.C1 = T2.C1
P2: T1.C2 = T2.C2
P3: T1.C3 = T2.C3

假设这两个表具有如下统计信息:

表 B.9
TABLENAMECOLNAMECOLCARDHIGH2KEYLOW2KEYTABLENAMECOLNAMECOLCARDHIGH2KEYLOW2KEY
T1C1100992T2C1109992
T1C21019991900T2C21019991900
T1C35'Y''B'T2C35'Y''B'

这个连接限定 DPF 条件,所以优化器可以使用范围统计信息来标识父表。在这个场景中,谓词 P2 和 P3 被表示为中立,这是由于两个表的 C2 和 C3 列的统计信息是等同的。然而,C1 的统计信息表明 T1 和 T2 都不是父表,也不把它看作是中立的,这是因为 T1.C1 具有一个更高的 COLCARD,而 T2.C1 具有一个更高的 HIGH2KEY 统计信息。因此,应该在 T1 或 T2 的列(C2 和 C3)上收集列组统计信息,这样优化器就可以检测连接谓词 P2 和 P3 间的统计相关性。

示例 B.10 无法使用 DPF 和范围统计信息

假设与 B.9 相同的场景,但是 T1 的分区键是在列(C1 和 C2)中,T2 的分区键在列(C2 和 C1)中。这个连接不满足第一个 DPF 条件,因为这两个表被认为不是在相同的列分区的;连接谓词 T1.C1=T2.C1 在 T1 的分区键中引用了第一个列,但在 T2 分区键中引用了第二个列。因此,优化器不能使用范围统计信息来标识父表,而只能使用 COLCARD 统计信息来确定父表。只在 COLCARD 的基础上,连接被认为是中立的。

示例 B.10.1 无法使用 DPF 和范围统计信息

假设与 B.10 相同的场景,但具有下列统计信息:

表 B.10
TABLENAMECOLNAMECOLCARDHIGH2KEYLOW2KEYTABLENAMECOLNAMECOLCARDHIGH2KEYLOW2KEY
T1C1100992T2C1989992
T1C21019991900T2C21119991900
T1C35'Y''B'T2C35'Y''B'

在 COLCARD 统计信息基础上,T1 是谓词 P1 的父表,而 T2 是谓词 P2 的父表。由于 COLCARD 统计信息被关闭,因此多列统计信息的偏差将降至 1% 以内,这是优化器在 DPF 环境中的容错值。在这里它可以使用简单方法,并且应在两个表的所有三个列中收集列组统计信息。之后,如果优化器没有计算出一个不同的基数估计值,那么说明并未达到 1% 的偏差。


附录 C. 有关本地谓词的更多详细资料

多列统计信息(索引和列组)只提供了一组列中不同组数量的信息。因此,说明统计相关性时,优化器假设数据是一致分布的。然而,本地等式谓词的选择性估计值则使用分布统计信息(如果可用)来计算,从而说明数据中的偏差。由于假设数据是一致的,而实际上数据是有偏差的,为避免高估本地等式谓词的组合选择性估计值,FixPak 10 中将对优化器的统计相关性检测做进一步改善。

参考资料

学习

获得产品和技术

  • 下载 DB2 Enterprise 9 的免费试用版本。
  • 现在您可以免费使用 DB2。下载 DB2 Express-C,这是为社区提供的 DB2 Express Edition 免费版本,它提供了和 DB2 Express Edition 相同的核心数据特性并为构建和部署应用程序奠定了坚实的基础。
  • 使用 IBM 试用软件 构建您的下一个开发项目,可直接从 developerWorks 下载。

讨论

条评论

developerWorks: 登录

标有星(*)号的字段是必填字段。


需要一个 IBM ID?
忘记 IBM ID?


忘记密码?
更改您的密码

单击提交则表示您同意developerWorks 的条款和条件。 查看条款和条件

 


在您首次登录 developerWorks 时,会为您创建一份个人概要。您的个人概要中的信息(您的姓名、国家/地区,以及公司名称)是公开显示的,而且会随着您发布的任何内容一起显示,除非您选择隐藏您的公司名称。您可以随时更新您的 IBM 帐户。

所有提交的信息确保安全。

选择您的昵称



当您初次登录到 developerWorks 时,将会为您创建一份概要信息,您需要指定一个昵称。您的昵称将和您在 developerWorks 发布的内容显示在一起。

昵称长度在 3 至 31 个字符之间。 您的昵称在 developerWorks 社区中必须是唯一的,并且出于隐私保护的原因,不能是您的电子邮件地址。

标有星(*)号的字段是必填字段。

(昵称长度在 3 至 31 个字符之间)

单击提交则表示您同意developerWorks 的条款和条件。 查看条款和条件.

 


所有提交的信息确保安全。


static.content.url=http://www.ibm.com/developerworks/js/artrating/
SITE_ID=10
Zone=Information Management
ArticleID=240626
ArticleTitle=理解 DB2 中的列组统计信息
publish-date=07162007