电脑技术学习

理解 DB2 中列组统计信息

dn001

  收集多列统计信息

  优化器考虑使用所有可用的索引 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 中使用这个子句。

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

  注重:假如启用了 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 表存在。

  为了创建 EXPLAIN 表,执行以下代码:

db2 -tvf $DB2PATH/misc/EXPLAIN.DDL


  创建了 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>


  使用您喜爱的文本编辑器,您应看到像下面这样的查询执行计划:

    2
   TBSCAN
   (  2)
   30.8464
    2
    |
    32
TABLE: SKAPOOR
  EMPLOYEE


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

  为这个查询添加几个冗余的等式谓词 :

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 优化器假设这三个谓词是彼此独立的,因为不存在相关的索引或列组统计信息。

  在 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.


  使用 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 包含一些示例,对判定连接中的父表做了进一步的分析。

  对 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 选项来显示为这些对象收集的统计信息。

  在 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;


  使用 db2look 工具查看 ORG 表的统计信息:

db2look -d sample -e -a -m -t ORG -o org.ddl


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

  在 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 创建索引,在多个表中收集多个列组统计信息:

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));


  查询目录表来检索列组统计信息。注重下面的查询是一个递归 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
;


  查询目录表以检索索引统计信息。

  注重:在 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 中,优化器使用了索引统计信息,而没有使用列组统计信息,通过说明统计信息相关性来修正基数估计值。

  尝试以下步骤:

  创建如下索引:

IXEMP_1 ON EMPLOYEE(JOB, WORKDEPT, SEX);
IXSTAFF_1 ON STAFF(ID, DEPT);
IXORG_1 ON ORG(MANAGER, DEPTNUMB);


  对这些索引收集统计信息,但不收集任何列组统计信息:

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 和 4 中的查询进行 EXPLAIN 处理。所得到的基数估计值符合上面的查询执行计划;然而,由于可用索引的不同,实际的计划会有所不同。注重收集的 DETAILED 统计信息并不影响基数估计值。
  丢弃步骤 1 中创建的 IXEMP_1 和 IXSTAFF_1 索引,创建两个新的索引:

IXEMP_1 ON EMPLOYEE(JOB, WORKDEPT, SEX, EMPNO);
IXSTAFF_1 ON STAFF(ID, DEPT,NAME,JOB);


  重复步骤 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 环境中,假如表跨多个数据库分区而被分区,在下列条件满足的情况下,只能使用范围统计信息:

  两个表在相同的列中被分区

  表是并置的,就是说,它们处于同一节点组

  连接谓词引用所有的分区键列

  在相同的节点收集统计信息

  假如不能够使用范围统计信息,那么优化器只能使用 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 列统计信息
  

COLNAME COLCARD HIGH2KEY LOW2KEY
DEPTNUMB 8 66 15
MANAGER 8 270 30
DEPT 8 66 15
ID 35 340 20

  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 中立连接统计信息
  

TABLENAME COLNAME COLCARD HIGH2KEY LOW2KEY TABLENAME COLNAME COLCARD HIGH2KEY LOW2KEY
T1 C1 100 99 2 T2 C1 100 99 2
T1 C2 10 1999 1900 T2 C2 10 1999 1900
T1 C3 5 'Y' 'B' T2 C3 5 'Y' 'B'

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

  示例 B.7

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

TABLENAME COLNAME COLCARD HIGH2KEY LOW2KEY TABLENAME COLNAME COLCARD HIGH2KEY LOW2KEY
T1 C1 100 99 2 T2 C1 10 99 2
T1 C2 10 1999 1900 T2 C2 10 1999 1900
T1 C3 5 'Y' 'B' T2 C3 5 '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 统计信息
  

TABLENAME COLNAME COLCARD HIGH2KEY LOW2KEY TABLENAME COLNAME COLCARD HIGH2KEY LOW2KEY
T1 C1 100 99 2 T2 C1 10 999 2
T1 C2 10 1999 1900 T2 C2 10 1999 1900
T1 C3 5 'Y' 'B' T2 C3 5 '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
  

TABLENAME COLNAME COLCARD HIGH2KEY LOW2KEY TABLENAME COLNAME COLCARD HIGH2KEY LOW2KEY
T1 C1 100 99 2 T2 C1 10 999 2
T1 C2 10 1999 1900 T2 C2 10 1999 1900
T1 C3 5 'Y' 'B' T2 C3 5 '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
  

TABLENAME COLNAME COLCARD HIGH2KEY LOW2KEY TABLENAME COLNAME COLCARD HIGH2KEY LOW2KEY
T1 C1 100 99 2 T2 C1 98 999 2
T1 C2 10 1999 1900 T2 C2 11 1999 1900
T1 C3 5 'Y' 'B' T2 C3 5 'Y' 'B'

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

  附录 C. 有关本地谓词的更多具体资料

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