级别: 初级
Larry Pay (lpay@ca.ibm.com), DB2 UDB 数据仓库顾问, IBM Software Services for DB2 Information Management
2005 年 1 月 01 日
RUNSTATS 是 DB2® Universal Database™(DB2 UDB)中的实用程序,它更新优化器为确定存取数据的最快路径所使用的目录统计信息。DB2 UDB V8.2 中,增加了相当多的 RUNSTATS 选项。理解如何使用 RUNSTATS 的现有选项和新选项可以帮助您获得最佳的数据库性能。为了阐明这一切,作者提供了许多示例。
RUNSTATS 为什么很重要?
现在,几乎所有重要数据库都使用某种方法来更新目录统计信息,以便为其优化器提供可能的最佳信息。可以将优化器视为一个勘探器,正在系统中的数据所代表的大山中进行定位。目录统计信息的更新将为优化器提供最新的地图,以便在整个地形中快速定位。
DB2 优化器使用目录统计信息来确定最佳的访问路径,而更新这些目录统计信息所采用的主要方法就是运行 RUNSTATS 实用程序。当用户表中发生数据修改时,目录统计信息表不会自动被修改。必须在表和索引上执行 RUNSTATS 命令,用最新的信息更新目录表中的列。
可以查询下列目录列,确定是否在表和索引上执行了 RUNSTATS:
如果对于某个表,SYSCAT.TABLES 视图的 CARD 列显示的值为 -1,或者 STATS_TIME 列显示的值为 NULL,那么这表示没有对该表运行 RUNSTATS 实用程序。
如果对于某个索引,SYSCAT.INDEXES 视图的 NLEAF、NLEVELS 和 FULLKEYCARD 列显示的值为 -1,或者 STATS_TIME 列显示的值为 NULL,那么这表示没有对该索引运行 RUNSTATS 实用程序。
在 第一次将数据载入到表中之后,就无法避免地要对表进行更新、删除和插入等形式的修改。可以添加或删除索引。特定列中的数据分布可能随时间发生改变。目录中 不会反映这些修改,除非在这些表和索引上执行 RUNSTATS。一段时间之后,随着表和数据发生更改,目录统计信息可能会过时。
执 行 RUNSTATS 是很重要的,但是频繁地运行可能会带来问题。对于较小的表,发出 RUNSTATS 命令将是一项普通任务。然而,随着表的增长,完成 RUNSTATS 命令将占用更多时间、CPU 和内存资源。最终,您必须考虑分配更多时间和资源来运行 RUNSTATS 与不执行该命令的潜在性能下降之间的平衡。通常只在关键查询的速度开始减慢时,管理员才会对 RUNSTATS 给予适当的注意。您可以通过制定高效、有效收集统计信息的策略,避免未经思考就调优查询和执行 RUNSTATS。
回页首
使用 RUNSTATS 收集目录统计信息
理论上,应该在下列情况下对表和索引执行 RUNSTATS:
将数据载入表中并创建了合适的索引之后。不过,最好是在创建索引之后再执行 LOAD 命令,并在 LOAD 期间收集统计信息。
创建了一个新的索引之后。
使用 REORG 实用程序重新组织表之后。
通过数据更新、删除和插入大量更新表及其索引之后。
更改了预取(prefetch)大小之后。
运行 REDISTRIBUTE DATABASE PARTITION GROUP 实用程序之后。
您可以通过比较查询 RUNSTATS 之前和之后的 EXPLAIN 输出,来确定运行 RUNSTATS 对于访问计划的影响。
完成每一条 RUNSTATS 语句之后,您都应该执行显式的 COMMIT WORK。COMMIT 将释放锁,并避免在收集多个表的统计信息时填写日志。
在用 RUNSTATS 收集了统计信息之后,要使用 BIND 命令或 REBIND 命令重新绑定包含了静态 SQL 的包(并可以选择重新解释其语句)。 db2rbind 命令可用于重新绑定数据库中的所有包。使用 FLUSH PACKAGE 命令来删除包缓存器中当前所有缓存的动态 SQL 语句,并强制隐式地编译下一请求。
下列例子说明如何使用 RUNSTATS 收集统计信息:
注意:在 RUNSTATS 语法中,必须使用全限定的表名 schema.table-name 和全限定的索引名 schema.index-name。您可以在所有列上,或者仅仅在某些列或列组(除了 LONG 和 LOB 列)上执行 RUNSTATS。如果没有指定特定列的子句,系统则会使用默认的 ON ALL COLUMNS 子句。
示例 1:收集所有列上的统计信息
RUNSTATS ON TABLE db2admin.department ON ALL COLUMNS
这等同于:
RUNSTATS ON TABLE db2admin.department
示例 2:收集单个列上的目录统计信息
RUNSTATS ON TABLE db2admin.department ON COLUMNS (deptno, deptname)
示例 3 展示如何收集关键列(key column)上的统计信息。短语“关键列(key column)”表示构成表上所定义索引的列。如果没有索引存在,这条命令不会收集任何列的统计信息。
示例 3:收集关键列上的目录统计信息
RUNSTATS ON TABLE db2admin.department ON KEY COLUMNS
示例 4:收集关键列上和一个非关键列上的目录统计信息
RUNSTATS ON TABLE db2admin.department ON KEY COLUMNS AND COLUMNS (deptname)
示例 5:收集表和索引上的目录统计信息,不包含分布统计信息
RUNSTATS ON TABLE db2admin.department AND INDEXES ALL
示例 6:收集表上的目录统计信息以及索引上的详细统计信息,不包含分布统计信息
RUNSTATS ON TABLE db2admin.department AND DETAILED INDEXES ALL
示例 7:只收集 3 个指定索引上的目录统计信息(不含表统计信息)
RUNSTATS ON TABLE db2admin.department FOR INDEXES db2admin.INX1, db2admin.INX2, db2admin.INX3
示例 8:只收集所有索引上的目录统计信息
RUNSTATS ON TABLE db2admin.department FOR INDEXES ALL
如果创建新的索引,而在最后一次执行 RUNSTATS 以后还未修改相应的表,那么您可以只收集索引上的目录统计信息。在创建索引时,还可以收集目录统计信息。我将在 收集目录统计信息的备选方法小节中讨论该方法。
回页首
使用 RUNSTATS WITH DISTRIBUTION
当您已确定表中包含不是统一分布的数据时,可以运行包含 WITH DISTRIBUTION 子句的 RUNSTATS。目录统计信息表通常包含关于表中最高和最低值的信息,而优化器假定数据值是在两个端点值之间均匀分布的。然而,如果数据值彼此之间差异 较大,或者群集在某些点上,或者是碰到许多重复的数据值,那么优化器就无法选择一个最佳的访问路径,除非收集了分布统计信息。使用 WITH DISTRIBUTION 子句还可以帮助查询处理没有参数标志符(parameter marker)或主机变量的谓词,因为优化器仍然不知道运行时的值是有许多行,还是只有少数行。
下列例子说明了使用 RUNSTATS 来收集包含分布的统计信息的不同方法:
示例 9:收集表和索引上的目录统计信息,包含分布统计信息
RUNSTATS ON TABLE db2admin.department WITH DISTRIBUTION AND INDEXES ALL
示例 10:收集表上的目录统计信息以及索引上的详细统计信息,包含分布统计信息
RUNSTATS ON TABLE db2admin.department WITH DISTRIBUTION AND DETAILED INDEXES ALL
示例 11:收集选定列中包含分布的目录统计信息
RUNSTATS ON TABLE db2admin.department WITH DISTRIBUTION ON COLUMNS (deptno, deptname)
示例 12:只收集表上的目录统计信息,包含 deptno 和 deptname 上的基本列统计信息以及 mgrno 和 admrdept 上的分布统计信息
RUNSTATS ON TABLE db2admin.department ON COLUMNS (deptno, deptname)
WITH DISTRIBUTION ON COLUMNS (mgrno, admrdept)
示例 13:收集构成索引的所有列以及两个非索引列中包含分布的目录统计信息
RUNSTATS ON TABLE db2admin.department WITH DISTRIBUTION ON KEY
COLUMNS AND COLUMNS (admrdept, location)
回页首
包含频率和分位数统计信息的 RUNSTATS
在执行包含 WITH DISTRIBUTION 子句的 RUNSTATS 时,会根据 RUNSTATS 命令中给定的选项选择一组频率(frequency)和分位数(quantile)的统计信息。
RUNSTATS 收集两种类型的数据分布统计信息:频率统计信息和分位数统计信息。
频率统计信息的默认值由 num_freqvalues 数据库配置参数控制,该值提供了重复最多的列和数据值的信息。其默认值是 10,建议将这个值设置在 10 到 100 之间。如果将 num_freqvalues 设置为零,则不保留任何频率值的统计信息。
分位数统计信息的默认值由 num_quantiles 数据库配置参数控制,该值提供了数据值对于其他值而言是如何分布的有关信息。 num_quantiles 数据库配置参数指定应将列数据值分成的组数。其默认值是 20,建议将该值设置在 20 到 50 之间。如果将这个参数设置为零或“1”,则不收集任何分位数统计信息。
如果没有在 RUNSTATS 命令的列或表级别上指定 num_freqvalues 和 num_quantiles,那么 num_freqvalues 的值将从 num_freqvalues 数据库配置参数中获取,而 num_quantiles 的值将从 num_quantiles 数据库配置参数中获取。
可以为单个列或一组列修改频率和分位数统计信息的精确度。提高分布统计信息的精确度将导致更大的 CPU 和内存消耗,并占用更多的目录空间。对于这些分布统计信息,只考虑对拥有选择谓词的最重要的查询而言最为重要的列。
当出现下列任何一种条件时,RUNSTATS 将不收集分布统计信息:
当将 num_freqvalues 配置参数设置为零(0),以及将 num_quantiles 数据库配置参数设置为零(0)或 1 时。
当每个数据值是惟一的时候。
当该列是 LONG、LOB 或结构化列时。
如果列中只有一个非空值。
扩展的索引或声明的临时表。
下列例子说明了使用 RUNSTATS 来收集目录统计信息和指定 num_freqvalues 和 num_quantiles 的不同方法:
假设 num_freqvalues 数据库配置参数值是 10, num_quantiles 数据库配置参数值是 20。
示例 14:收集包含分布统计信息的目录统计信息
RUNSTATS ON TABLE db2admin.department WITH DISTRIBUTION AND INDEXES ALL
将 num_freqvalues parameter 设置为 10, num_quantiles parameter 设置为 20,因为在命令行上没有指定 num_freqvalues 和 num_quantiles 参数。
示例 15:仅收集表上的目录统计信息,其中使用指定的 num_freqvalues 以及从数据库配置设置选择 num_quantiles 收集所有列上的分布统计信息
RUNSTATS ON TABLE db2admin.department WITH DISTRIBUTION DEFAULT
NUM_FREQVALUES 40
将 num_freqvalues 参数设置为 40, num_quantiles 参数设置为 20。
示例 16:收集表上的目录统计信息,包含列 deptno 和 deptname 上的分布统计信息。单独为 deptname 列设置分布统计信息的范围,而 deptno 列使用公共的默认值。并且还为两个索引 IDX1 和 IDX2 收集目录统计信息。
RUNSTATS ON TABLE db2admin.department WITH DISTRIBUTION ON COLUMNS
(deptno, deptname NUM_FREQVALUES 50 NUM_QUANTILES 100) DEFAULT
NUM_FREQVALUES 5 NUM_QUANTILES 10 AND INDEXES db2admin.IDX1, db2admin.IDX2
对于 deptname 列, num_freqvalues 是 50, num_quantiles 是 100。
对于 deptno 列, num_freqvalues 5, num_quantiles 是 10。
示例 17:收集所有索引上的目录统计信息,包含列 deptname 上的分布统计信息。未列出的列上的分布统计信息将被清除。
RUNSTATS ON TABLE db2admin.department WITH DISTRIBUTION ON COLUMNS
(deptname NUM_FREQVALUES 20 NUM_QUANTILES 40)
AND INDEXES ALL
对于 deptname 列, num_freqvalues 是 20, num_quantiles 是 40。
示例 18:收集所有索引以及列 deptno 和 deptname 上的目录统计信息。deptno 列的 num_freqvalues 和 num_quantiles 值将从默认值中获得。
RUNSTATS ON TABLE db2admin.department WITH DISTRIBUTION ON COLUMNS
(deptno, deptname NUM_FREQVALUES 20 NUM_QUANTILES 40) DEFAULT
NUM_FREQVALUES 0 NUM_QUANTILES 0 AND INDEXES ALL
对于 deptname 列, num_freqvalues 是 20, num_quantiles 是 40。
对于 deptno 列, num_freqvalues 是 0, num_quantiles 是 0。
其他所有列不包含任何统计信息。
回页首
包含列组统计信息的 RUNSTATS
列组(Column Group)统计信息将获得一组列的不同值组合的数目。通常,DB2 优化器可用的基本统计信息不检测数据相关性。列组的使用将给多个谓词的联合选择提供更准确的估计。列组统计信息假设数据是均匀分布的;但还无法获得列组上的分布统计信息。
较于列组的基数,单个列的基数(cardinality)的乘积将获得更好的相关性估计。
下列例子说明了如何使用 RUNSTATS 收集捕获了列组信息的目录统计信息:
示例 19:收集捕获了列组的目录统计信息
RUNSTATS ON TABLE db2admin.department ON COLUMNS ((deptno, deptname),
deptname, mrgno, (admrdept, location))
本例中,总共有两个列组:(deptno, deptname) 和 (admrdept, location)。
回页首
包含 LIKE STATISTICS 的 RUNSTATS
当在 RUNSTATS 中指定 LIKE STATISTICS 子句时,将收集附加的列统计信息。这些统计信息存储在 SYSIBM.SYSCOLUMNS 表里的 SUB_COUNT 和 SUB_DELIM_LENGTH 列中。它们仅针对字符串列进行收集,查询优化器用它们来提高“column LIKE ‘%abc‘”和“column LIKE ‘%abc%‘”类型谓词的选择性估计。
下列例子说明了如何使用 RUNSTATS 收集捕获了 LIKE 统计信息的目录统计信息:
示例 20:收集所有列上的目录统计信息并指定 VARCHAR 列上的 LIKE 统计信息
RUNSTATS ON TABLE db2admin.department ON ALL COLUMNS and COLUMNS (deptname LIKE STATISTICS)
回页首
包含统计信息配置文件的 RUNSTATS
现在,可以在 DB2 V8.2 中为 RUNSTATS 建立一个统计信息的配置文件。统计信息配置文件是指一组选项,它预先定义了特定表上将要收集的统计信息。
当将命令参数“SET PROFILE”添加到 RUNSTATS 命令时,将在表描述符和系统目录中注册或存储统计信息配置文件。若要更新该统计信息配置文件,则可以使用命令参数“UPDATE PROFILE”。
没有删除配置文件的选项。
下列例子展示了如何使用这项功能:
示例 21:只注册一个统计信息配置文件,不收集目录统计信息
RUNSTATS ON TABLE db2admin.department AND INDEXES ALL SET PROFILE ONLY
RUNSTATS 中的子句“SET PROFILE ONLY”不收集统计信息。
示例 22:注册一个统计信息配置文件,并执行所存储统计信息配置文件的 RUNSTATS 命令选项来收集目录统计信息
RUNSTATS ON TABLE db2admin.department AND INDEXES ALL SET PROFILE
示例 23:仅修改现有的统计信息配置文件,不收集任何目录统计信息
RUNSTATS ON TABLE db2admin.department WITH DISTRIBUTION AND INDEXES ALL UPDATE PROFILE ONLY
示例 24:修改现有的统计信息配置文件,并执行已更新的统计信息配置文件的 RUNSTATS 命令选项来收集目录统计信息
RUNSTATS ON TABLE db2admin.department WITH DISTRIBUTION AND INDEXES ALL UPDATE PROFILE
示例 25:根据前面已注册的统计信息配置文件来查询 RUNSTATS 选项
SELECT STATISTICS_PROFILE FROM SYSIBM.SYSTABLES WHERE NAME = ‘DEPARTMENT‘ AND CREATOR = ‘DB2ADMIN‘
示例 26:使用前面已注册的统计信息配置文件收集目录统计信息
RUNSTATS ON TABLE db2admin.department USE PROFILE
回页首
带有抽样的 RUNSTATS
随着数据库快速不断地增长,通过访问所有数据收集统计信息的能力可能会受到固定的批量窗口、内存和 CPU 约束的阻碍。
目前,要运行表上的 RUNSTATS,就要执行全表扫描。通过数据抽样,只需扫描数据的一个子集即可。
如果一个查询试图预计总的趋势和模式,且某一误差域(margin of error)内的近似答案足以监测这些趋势和模式,那么数据抽样或许是比全表扫描更好的选择。
在 DB2 V8.1 中,引入了 SAMPLED DETAILED 子句,允许通过抽样计算详细的索引统计信息。该子句的使用将减少为获得详细索引统计信息而执行的后台计算量和所需的时间,但在大多数情况下,都会使数据足够的精确。
以下是一些关于该子句的使用的例子:
示例 27:收集两个索引上的详细目录统计信息,但对每个索引条目使用抽样来代替执行详细的计算
RUNSTATS ON TABLE db2admin.department AND SAMPLED DETAILED INDEXES ALL
示例 28:收集索引上的详细抽样统计信息和表的分布统计信息
RUNSTATS ON TABLE db2admin.department WITH DISTRIBUTION ON KEY
COLUMNS AND SAMPLED DETAILED INDEXES ALL
在 DB2 V8.2 中,提供了对表数据进行抽样的两种新方法:行级的贝努里(Bernoulli)抽样和系统页级的抽样。
回页首
带有行级贝努里(Bernoulli)抽样的 RUNSTATS
行 级贝努里(Bernoulli)抽样利用 sargable(search + argument-able 谓词是一个可以由数据管理器来评估的谓词)谓词获得百分之 P 的表行样本,在样本中包含每一行的概率是 P/100,而不包含它的概率则是 1 - P/100。
例如,对于 10% 贝努里(Bernoulli)抽样,将会选择 10%(10/100)的行,而拒绝 90%(1-10/100)的行。在贝努里(Bernoulli)抽样中,每一页将会引发一次 I/O,因为要扫描该表。将生成一个随机数来确定是否选择一行(类似于以 P/100 的概率扔钱币)。即使每一页都发生一次 I/O,我们仍然节省了处理数据所需的 CPU 时间。
在行级贝努里(Bernoulli)抽样中,需要读取每一个数据页。然而,它仍然可以带来极大的性能提高,因 为 RUNSTATS 是 CPU 密集的。如果索引是可用的,那么就会改进抽样。如果数据是群集的,它还可以提供更准确的统计信息(所获得的样本更好地代表了整个表数据)。
回页首
带有系统页级抽样的 RUNSTATS
系 统页级抽样与行级抽样类似,除了抽样的对象是页面而不是行。以 P/100 的概率选择每一页,而以 1 - P/100 的概率拒绝页的选择。在所选中的每一页中,要选择所有的行。系统页级抽样优于全表扫描或贝努里(Bernoulli)抽样的地方是它节省了 I/O。
抽样页也是预取的,所以该方法将比行级贝努里(Bernoulli)抽样更快。与不进行抽样相比,页级抽样极大地提高了性能。
RUNSTATS repeatable 子句允许通过 RUNSTATS 语句生成相同的样本,只要表数据没有发生更改。为了指定该选项,用户还必须提供一个整数,以表示将用于生成样本的种子(seed)。通过使用相同的种子,可以生成相同的样本。
总之,统计信息的准确性取决于抽样率、数据倾斜(data skew)以及用于数据抽样的数据群集。
下面是一些使用贝努里(Bernoulli)行级和系统页级抽样的 RUNSTATS 例子:
示例 29:收集统计信息,包含 10% 行上的分布统计信息
RUNSTATS ON TABLE db2admin.department WITH DISTRIBUTION TABLESAMPLE BERNOULLI (10)
示例 30:为了控制收集统计信息的样本集,以及可以重复使用相同的样本集,需要使用下列语句:
RUNSTATS ON TABLE db2admin.department WITH DISTRIBUTION TABLESAMPLE
BERNOULLI (10) REPEATABLE (1024)
示例 31:收集 10% 的数据页上的索引统计信息和表统计信息。请注意,只对表数据页进行抽样,而不是索引页。本例中,10% 的表数据页用于表统计信息的收集,而对于索引统计信息,将使用所有的索引页。
RUNSTATS ON TABLE db2admin.department AND INDEXES ALL TABLESAMPLE SYSTEM (10)
回页首
收集目录统计信息的可供选择的方法
对于数据库中的所有表,收集统计信息的一个可供选择的方法就是发出一条 REORGCHK 命令,如下所示:
示例 32:使用 REORGCHK 收集所有表的目录统计信息
REORGCHK UPDATE STATISTICS ON TABLE ALL
reorgchk 命令的 update statistics 选项的作用类似于调用 RUNSTATS 例程来更新数据库中所有表的目录统计信息,但是所有列上的统计信息只能通过默认的 RUNSTATS 选项来收集。通过使用该命令,还可以收集单个表上或同一模式下一组表的统计信息。
示例 33:使用 REORGCHK 收集一个表的目录统计信息
REORGCHK UPDATE STATISTICS ON TABLE db2admin.department
示例 34:使用 REORGCHK 收集一个模式的目录统计信息
REORGCHK UPDATE STATISTICS ON SCHEMA systools
虽然该方法看上去是一种在多个表上收集目录统计信息的快速方法,但是仅仅当 REORGCHK 可以在合理的时间内完成执行时,该方法才是可取的。
在表的 LOAD REPLACE 期间以及索引的创建期间,也可以进行目录统计信息的收集。
在 UDB V8.2 中,为了在 LOAD 期间调用目录统计信息的收集,必须将选项“STATISTICS USE PROFILE”添加到 LOAD 控制语句中。选项“STATISTICS YES”仍然有用,但它现在已是过时的语法。若在表的 LOAD 之后在同一表上执行 RUNSTATS,那么在 LOAD 期间发出“STATISTICS USE PROFILE”的目的就是为了减少正常运行过程中占用的时间。在执行 load 之前,就必须创建统计信息配置文件,它现在允许指定与 RUNSTATS 命令中相同的统计信息选项。
示例 35:使用 LOAD 命令和 STATISTICS USE PROFILE 子句收集目录统计信息
LOAD FROM inputfile.del OF DEL REPLACE INTO db2admin.department STATISTICS USE PROFILE
大多数情况下,RUNSTATS 是在创建索引之后执行的。然而,在执行索引创建操作时,也能收集索引的统计信息。这将避免为了收集统计信息而进行的另一项索引扫描。下列例子说明了完成这项工作可以使用的一些选项:
示例 36:收集基本的索引目录统计信息:
CREATE INDEX db2admin.inx1 ON db2admin.department (deptno) COLLECT STATISTICS
示例 37:收集扩展的索引目录统计信息:
CREATE INDEX db2admin.inx2 ON db2admin.department (deptname) COLLECT DETAILED STATISTICS
示例 38:收集扩展的索引目录统计信息,指定使用抽样:
CREATE INDEX db2admin.inx3 ON db2admin.department (deptname) COLLECT SAMPLED DETAILED STATISTICS
回页首
包含授权和用户访问的 RUNSTATS
为了可以对一个表或索引收集统计信息,必须能够连接到包含该表和索引的数据库,并具有下列授权级别之一:
sysadm
sysctrl
sysmaint
dbadm
表上的 CONTROL 权限
当对一个表运行 RUNSTATS 时,有两种用户访问选项:允许读访问和允许写访问。
在 RUNSTATS 命令中的参数 ALLOW READ ACCESS 指定计算统计信息时,其他用户可以只读地访问该表。
在 RUNSTATS 命令中的参数 ALLOW WRITE ACCESS 指定计算统计信息时,其他用户可以读取或写入该表。如果该表在任何时刻都必须是可用的,那么应该使用该子句。
回页首
分区数据库中的 RUNSTATS
当 在一个分区数据库中发出 RUNSTATS 命令,并且一个表分区位于发出 RUNSTATS 的数据库分区中时,那么 RUNSTATS 将在该数据库分区上执行。如果表分区不在该数据库分区上,那么将请求发送给数据库分区组中持有该表分区的第一个数据库分区。然后,在该数据库分区上执行 RUNSTATS 命令。
RUNSTATS 不是在分区的数据库中并行运行的,但对一个分区确定信息,然后对所有分区推断出合适的估计值。有一个隐式的假设:每个表中的行是均匀分布在每个多分区数据库分区组中的所有分区上的。
下列 IBM 技术札记(technote)谈到了加载一个表时运行 RUNSTATS 可能碰到的问题。其解决方案就是确保在加载表之前,为该表定义一个分区键(partitioning key)。
IBM Technote # 1153232(2004-02-12):
“加载表之后,Runstats 将多分区实例上 syscat.tables 中的列 CARD 更新为零行。
摘要
如果加载某一给定表之后,其中一个分区的行数为零,并且将从该分区执行 runstats,那么该命令将更新 syscat. 表中的列 CARD,显示该表的行数为零。这只对多分区的实例有影响。
内容
runstats 的行为使其将使用运行它的分区上的数据来推测该表中的行数。例如,如果加载之后所有数据都在一个分区上,并从另一分区执行 runstats,那么该命令将更新 syscat.tables 来表示该表的行数为零。然而,如果是从保存所有数据的分区运行 runstats,那么它将更新 syscat.tables 来展示该表包含((该分区上的行数)x(分区数目))行。
为了避免 runstats 的行为默认行为,需要在加载表之前,为该表定义分区键(partitioning key)。分区键需要位于高度惟一的一列或一组列上,从而确保数据均匀分布在该表所定义的所有分区上。”
回页首
调整 STAT_HEAP_SZ 数据库配置参数
stat_heap_sz 或统计信息堆大小的数据库配置参数指定了使用 RUNSTATS 命令收集统计信息中所用堆的最大尺寸。它是在启动 RUNSTATS 实用程序时分配的,然后当它完成时释放。stat_heap_sz 是代理私有内存的一部分。因此,在收集分布统计信息时,最好增大 stat_heap_sz 参数,以便能将更多的列放入这个堆中。处理较宽的表也需要更多的内存。当执行包含 SAMPLED DETAILED 选项的 RUNSTATS 时,必须额外分配 2 MB 内存,以确保 RUNSTATS 能够成功运行。
回页首
减小 RUNSTATS 对系统性能影响的策略
您可以使用下列策略来帮助减小 RUNSTATS 对于系统的性能影响:
一次仅在少数表和索引上运行 RUNSTATS,在整组表中循环运行。
仅指定将收集其数据分布统计信息的那些列。仅指定那些谓词中所使用的列。
对于不同的表,在不同的分区上实现多个并发的 RUNSTATS。
仅在那些影响当前工作负载的关键表上执行 RUNSTATS。避免在不需要它的表上运行 RUNSTATS。
根据表中数据发生改变的速度,调整 RUNSTATS 的频率。
根据 RUNSTATS 在该表上完成运行的速度,调整 RUNSTATS 的频率和细节。
仅在系统活动量少的时候,安排执行 RUNSTATS。
调整(Throttle)RUNSTATS,以便最大程度地减少它对系统的需求。
仅在系统活动量少的时候安排执行 RUNSTATS,这是最大程度地减少系统影响的一个好方法。然而,对于一个 24 x 7 的系统,系统中可能没有可用的窗口或活动量少的时候。处理该情形的一种方法就是使用 RUNSTATS 的 throttling 选项。
throttling 选项将根据当前的数据库活动级别,来限制实用程序所占有的资源数量。UDB 中,在调整时,util_impact_lim 与 UTIL_IMPACT_PRIORITY 参数的交互确定了 RUNSTATS 的行为。UTIL_IMPACT_PRIORITY 关键字被用于诸如 RUNSTATS 的实用程序命令的子句中,而 util_impact_lim 则是一个实例配置参数。
util_impact_lim 参数是指允许所有已调整实用程序对于实例的工作负载产生影响的百分比。如果 util_impact_lim 是 100(默认值),则不用调整诸如 RUNSTATS 之类的实用程序调用。例如,如果将 util_impact_lim 设置为 10,那么已调整的 RUNSTATS 调用就被限定在消耗 10% 以下的工作负载。
UTIL_IMPACT_PRIORITY 关键字可充当一个开关,它指定 RUNSTATS 是否订阅调整策略。
示例 39:UTIL_IMPACT_PRIORITY 关键字的使用
RUNSTATS ON TABLE db2admin.department AND INDEXES ALL UTIL_IMPACT_PRIORITY 10
其中,10 是调整 RUNSTATS 的优先权或级别。
当 util_impact_lim 不是 100,而且用 UTIL_IMPACT_PRIORITY 调用 RUNSTATS 时,将会对该值进行调整。如果没有为 UTIL_IMPACT_PRIORITY 指定优先权,且 util_impact_lim 不是 100,那么 RUNSTATS 将使用默认的优先权 50,并将据此进行调整。如果在 RUNSTATS 命令中省略 UTIL_IMPACT_PRIORITY 关键字,那么可以不加调整地运行 RUNSTATS。如果指定了优先权,但是将 util_impact_limit 设置为 100,也可以不加调整地运行 RUNSTATS。如果将优先权设置为零,也能不加调整地运行 RUNSTATS。
当定义了 RUNSTATS 调整(throttling),并且该调整可操作时,RUNSTATS 实用程序预计将花费更长时间,但是对系统产生的影响会少一些。
回页首
RUNSTATS 的其他问题
已声明的全局临时表上的 RUNSTATS
可 以在已声明的全局临时表(DGTT)上发出 RUNSTATS 命令,但是结果的统计信息不存储在系统目录中,因为声明的临时表条目没有目录条目。这些统计信息存储在表示声明的临时表的目录信息的内存结构中。如果整个 查询经过时间中所节省的时间比完成 RUNSTATS 所增加的时间大得多,就建议发出 RUNSTATS。
可以在 SQL 例程(过程、UDF 和方法)中发出 RUNSTATS 命令吗?
下列 IBM 技术札记(technote)讨论了该问题:
IBM Technote # 1153051
“既不能从 SQL 例程(过程、UDF、方法)、SQL 动态复合语句发出 RUNSTATS 命令,也不能使用从 SQL 例程中发出的操作系统调用来发出该命令。如果需要发出 RUNSTATS 命令,那么可以直接从命令行处理器(Command Line Processor,CLP)发出它,或者通过使用 db2Runstats() API 函数(DB2 8.1 开始)从客户机应用程序或外部语言例程发出它,以及通过 LOAD 和 CREATE INDEX 语句发出该命令。”
可以创建一个名为“runstats”的 C 存储过程,调用 db2Runstats() API 函数。然后,可以使用 CALL 命令调用这个 C 存储过程。
如何通过调用级接口(CLI)或 Java 执行 RUNSTATS 来收集统计信息?
下列 IBM 技术札记回答了该问题:
IBM Technote # 1023788:
“DB2 管理 API(编程接口)sqlustat 可以用于从 DB2 应用程序发出 RUNSTATS,例如写入调用级接口的应用程序。DB2 Administrative API Reference 手册中描述了 sqlustat。”
回页首
DB2 自动统计信息收集
DB2 自动统计信息收集是在 DB2 UDB Version 8.2 中引入的。自动统计信息收集是完全自动表维护解决方案的一部分。其目标是允许 DB2 确定工作负载需要哪些统计信息,并定期在后台自动运行 RUNSTATS 实用程序,以便按需更新统计信息。
为了设置 SAMPLE 数据库自动进行统计信息收集,需要为自动维护开关设置数据库配置参数,如下所示:
db2 update db cfg for SAMPLE using AUTO_MAINT ON
db2 update db cfg for SAMPLE using AUTO_TBL_MAINT ON
db2 update db cfg for SAMPLE using AUTO_RUNSTATS ON
下图(只显示统计信息收集和配置选项)展示了统计信息收集和配置的自动维护命令的层次结构和相关性。在该结构中,可以在最高层次快速关闭自动维护参数 AUTO_MAINT,而不丢失较低层的配置设置,比如 AUTO_RUNSTATS。
图 1. 自动维护设置
如 果需要自动统计信息配置,那么可以打开参数 AUTO_STATS_PROF 和 AUTO_PROF_UPD。自动统计信息配置则通过确定何时和如何收集统计信息更进了一步。统计信息配置文件是自动生成的,自动统计信息收集过程将用它 来调度 RUNSTATS。可以用内部算法来比较新收集的统计信息与已保存的一组统计信息,并基于某些触发条件发出包含抽样的 RUNSTATS。
当启用自动统计信息配置时,数据库活动的有关信息被收集并存储在查询反馈仓库中。然后,基于查询反馈仓库中的数据生成统计配置文件。
为了允许自动生成统计信息配置文件,需要设置两个数据库配置参数:
db2 update db cfg for SAMPLE using AUTO_STATS_PROF ON
打开该参数将启动查询反馈数据的收集。
db2 update db cfg for SAMPLE using AUTO_PROF_UPD ON
打开该参数,指定使用分析查询反馈数据的 DB2 中的建议来更新 RUNSTATS 配置文件。
在触发自动统计信息配置之前,必须通过运行 SYSINSTALLOBJECTS 存储过程创建查询反馈仓库。
按照下列方式调用该存储过程:
call SYSINSTALLOBJECTS ( toolname , action , tablespacename , schemaname )
其中,toolname 是“ASP”或“AUTO STATS PROFILING”,对于 action,“C”表示创建,“D”表示删除。
目前,不使用参数 schemaname。
例如,要创建反馈仓库,需要运行下列存储过程:
call SYSINSTALLOBJECTS (‘ASP‘, ‘C‘, ‘USERSPACE1‘, ‘‘)
该过程将创建下列表、存储建议以及与查询执行过程中碰到的谓词有关的信息:
SYSTOOLS.OPT_FEEDBACK_QUERY
SYSTOOLS.OPT_FEEDBACK_PREDICATE
SYSTOOLS.OPT_FEEDBACK_PREDICATE_COLUMN
SYSTOOLS.OPT_FEEDBACK_RANKING
SYSTOOLS.OPT_FEEDBACK_RANKING_COLUMN
当禁用 AUTO_PROF_UPD 参数时,可以将建议存储在 SYSTOOLS.OPT_FEEDBACK_RANKING 表中。然后,当手动更新 RUNSTATS 配置文件时,就可以查看该表中所存储的建议。
DB2 自动统计信息收集和配置生成只能在 DB2 串行模式下启用;它们在联邦的、SMP 和 MPP 环境中是不可用的。
回页首
结束语
理 解并正确使用 RUNSTATS 是维护高性能数据库的关键之一。本文讨论了 RUNSTATS 的重要性,并解释了许多使 RUNSTATS 更有用的可用选项,其中包括 V8.2 中的一些新选项,通过允许建立指定需要为每个表收集哪些统计信息的配置文件,这些新选项简化了管理。我所展示的示例将使您易于使用 RUNSTATS 获得最佳的数据库性能。
Larry Pay (lpay@ca.ibm.com), DB2 UDB 数据仓库顾问, IBM Software Services for DB2 Information Management
2005 年 1 月 01 日
RUNSTATS 是 DB2® Universal Database™(DB2 UDB)中的实用程序,它更新优化器为确定存取数据的最快路径所使用的目录统计信息。DB2 UDB V8.2 中,增加了相当多的 RUNSTATS 选项。理解如何使用 RUNSTATS 的现有选项和新选项可以帮助您获得最佳的数据库性能。为了阐明这一切,作者提供了许多示例。
RUNSTATS 为什么很重要?
现在,几乎所有重要数据库都使用某种方法来更新目录统计信息,以便为其优化器提供可能的最佳信息。可以将优化器视为一个勘探器,正在系统中的数据所代表的大山中进行定位。目录统计信息的更新将为优化器提供最新的地图,以便在整个地形中快速定位。
DB2 优化器使用目录统计信息来确定最佳的访问路径,而更新这些目录统计信息所采用的主要方法就是运行 RUNSTATS 实用程序。当用户表中发生数据修改时,目录统计信息表不会自动被修改。必须在表和索引上执行 RUNSTATS 命令,用最新的信息更新目录表中的列。
可以查询下列目录列,确定是否在表和索引上执行了 RUNSTATS:
如果对于某个表,SYSCAT.TABLES 视图的 CARD 列显示的值为 -1,或者 STATS_TIME 列显示的值为 NULL,那么这表示没有对该表运行 RUNSTATS 实用程序。
如果对于某个索引,SYSCAT.INDEXES 视图的 NLEAF、NLEVELS 和 FULLKEYCARD 列显示的值为 -1,或者 STATS_TIME 列显示的值为 NULL,那么这表示没有对该索引运行 RUNSTATS 实用程序。
在 第一次将数据载入到表中之后,就无法避免地要对表进行更新、删除和插入等形式的修改。可以添加或删除索引。特定列中的数据分布可能随时间发生改变。目录中 不会反映这些修改,除非在这些表和索引上执行 RUNSTATS。一段时间之后,随着表和数据发生更改,目录统计信息可能会过时。
执 行 RUNSTATS 是很重要的,但是频繁地运行可能会带来问题。对于较小的表,发出 RUNSTATS 命令将是一项普通任务。然而,随着表的增长,完成 RUNSTATS 命令将占用更多时间、CPU 和内存资源。最终,您必须考虑分配更多时间和资源来运行 RUNSTATS 与不执行该命令的潜在性能下降之间的平衡。通常只在关键查询的速度开始减慢时,管理员才会对 RUNSTATS 给予适当的注意。您可以通过制定高效、有效收集统计信息的策略,避免未经思考就调优查询和执行 RUNSTATS。
回页首
使用 RUNSTATS 收集目录统计信息
理论上,应该在下列情况下对表和索引执行 RUNSTATS:
将数据载入表中并创建了合适的索引之后。不过,最好是在创建索引之后再执行 LOAD 命令,并在 LOAD 期间收集统计信息。
创建了一个新的索引之后。
使用 REORG 实用程序重新组织表之后。
通过数据更新、删除和插入大量更新表及其索引之后。
更改了预取(prefetch)大小之后。
运行 REDISTRIBUTE DATABASE PARTITION GROUP 实用程序之后。
您可以通过比较查询 RUNSTATS 之前和之后的 EXPLAIN 输出,来确定运行 RUNSTATS 对于访问计划的影响。
完成每一条 RUNSTATS 语句之后,您都应该执行显式的 COMMIT WORK。COMMIT 将释放锁,并避免在收集多个表的统计信息时填写日志。
在用 RUNSTATS 收集了统计信息之后,要使用 BIND 命令或 REBIND 命令重新绑定包含了静态 SQL 的包(并可以选择重新解释其语句)。 db2rbind 命令可用于重新绑定数据库中的所有包。使用 FLUSH PACKAGE 命令来删除包缓存器中当前所有缓存的动态 SQL 语句,并强制隐式地编译下一请求。
下列例子说明如何使用 RUNSTATS 收集统计信息:
注意:在 RUNSTATS 语法中,必须使用全限定的表名 schema.table-name 和全限定的索引名 schema.index-name。您可以在所有列上,或者仅仅在某些列或列组(除了 LONG 和 LOB 列)上执行 RUNSTATS。如果没有指定特定列的子句,系统则会使用默认的 ON ALL COLUMNS 子句。
示例 1:收集所有列上的统计信息
RUNSTATS ON TABLE db2admin.department ON ALL COLUMNS
这等同于:
RUNSTATS ON TABLE db2admin.department
示例 2:收集单个列上的目录统计信息
RUNSTATS ON TABLE db2admin.department ON COLUMNS (deptno, deptname)
示例 3 展示如何收集关键列(key column)上的统计信息。短语“关键列(key column)”表示构成表上所定义索引的列。如果没有索引存在,这条命令不会收集任何列的统计信息。
示例 3:收集关键列上的目录统计信息
RUNSTATS ON TABLE db2admin.department ON KEY COLUMNS
示例 4:收集关键列上和一个非关键列上的目录统计信息
RUNSTATS ON TABLE db2admin.department ON KEY COLUMNS AND COLUMNS (deptname)
示例 5:收集表和索引上的目录统计信息,不包含分布统计信息
RUNSTATS ON TABLE db2admin.department AND INDEXES ALL
示例 6:收集表上的目录统计信息以及索引上的详细统计信息,不包含分布统计信息
RUNSTATS ON TABLE db2admin.department AND DETAILED INDEXES ALL
示例 7:只收集 3 个指定索引上的目录统计信息(不含表统计信息)
RUNSTATS ON TABLE db2admin.department FOR INDEXES db2admin.INX1, db2admin.INX2, db2admin.INX3
示例 8:只收集所有索引上的目录统计信息
RUNSTATS ON TABLE db2admin.department FOR INDEXES ALL
如果创建新的索引,而在最后一次执行 RUNSTATS 以后还未修改相应的表,那么您可以只收集索引上的目录统计信息。在创建索引时,还可以收集目录统计信息。我将在 收集目录统计信息的备选方法小节中讨论该方法。
回页首
使用 RUNSTATS WITH DISTRIBUTION
当您已确定表中包含不是统一分布的数据时,可以运行包含 WITH DISTRIBUTION 子句的 RUNSTATS。目录统计信息表通常包含关于表中最高和最低值的信息,而优化器假定数据值是在两个端点值之间均匀分布的。然而,如果数据值彼此之间差异 较大,或者群集在某些点上,或者是碰到许多重复的数据值,那么优化器就无法选择一个最佳的访问路径,除非收集了分布统计信息。使用 WITH DISTRIBUTION 子句还可以帮助查询处理没有参数标志符(parameter marker)或主机变量的谓词,因为优化器仍然不知道运行时的值是有许多行,还是只有少数行。
下列例子说明了使用 RUNSTATS 来收集包含分布的统计信息的不同方法:
示例 9:收集表和索引上的目录统计信息,包含分布统计信息
RUNSTATS ON TABLE db2admin.department WITH DISTRIBUTION AND INDEXES ALL
示例 10:收集表上的目录统计信息以及索引上的详细统计信息,包含分布统计信息
RUNSTATS ON TABLE db2admin.department WITH DISTRIBUTION AND DETAILED INDEXES ALL
示例 11:收集选定列中包含分布的目录统计信息
RUNSTATS ON TABLE db2admin.department WITH DISTRIBUTION ON COLUMNS (deptno, deptname)
示例 12:只收集表上的目录统计信息,包含 deptno 和 deptname 上的基本列统计信息以及 mgrno 和 admrdept 上的分布统计信息
RUNSTATS ON TABLE db2admin.department ON COLUMNS (deptno, deptname)
WITH DISTRIBUTION ON COLUMNS (mgrno, admrdept)
示例 13:收集构成索引的所有列以及两个非索引列中包含分布的目录统计信息
RUNSTATS ON TABLE db2admin.department WITH DISTRIBUTION ON KEY
COLUMNS AND COLUMNS (admrdept, location)
回页首
包含频率和分位数统计信息的 RUNSTATS
在执行包含 WITH DISTRIBUTION 子句的 RUNSTATS 时,会根据 RUNSTATS 命令中给定的选项选择一组频率(frequency)和分位数(quantile)的统计信息。
RUNSTATS 收集两种类型的数据分布统计信息:频率统计信息和分位数统计信息。
频率统计信息的默认值由 num_freqvalues 数据库配置参数控制,该值提供了重复最多的列和数据值的信息。其默认值是 10,建议将这个值设置在 10 到 100 之间。如果将 num_freqvalues 设置为零,则不保留任何频率值的统计信息。
分位数统计信息的默认值由 num_quantiles 数据库配置参数控制,该值提供了数据值对于其他值而言是如何分布的有关信息。 num_quantiles 数据库配置参数指定应将列数据值分成的组数。其默认值是 20,建议将该值设置在 20 到 50 之间。如果将这个参数设置为零或“1”,则不收集任何分位数统计信息。
如果没有在 RUNSTATS 命令的列或表级别上指定 num_freqvalues 和 num_quantiles,那么 num_freqvalues 的值将从 num_freqvalues 数据库配置参数中获取,而 num_quantiles 的值将从 num_quantiles 数据库配置参数中获取。
可以为单个列或一组列修改频率和分位数统计信息的精确度。提高分布统计信息的精确度将导致更大的 CPU 和内存消耗,并占用更多的目录空间。对于这些分布统计信息,只考虑对拥有选择谓词的最重要的查询而言最为重要的列。
当出现下列任何一种条件时,RUNSTATS 将不收集分布统计信息:
当将 num_freqvalues 配置参数设置为零(0),以及将 num_quantiles 数据库配置参数设置为零(0)或 1 时。
当每个数据值是惟一的时候。
当该列是 LONG、LOB 或结构化列时。
如果列中只有一个非空值。
扩展的索引或声明的临时表。
下列例子说明了使用 RUNSTATS 来收集目录统计信息和指定 num_freqvalues 和 num_quantiles 的不同方法:
假设 num_freqvalues 数据库配置参数值是 10, num_quantiles 数据库配置参数值是 20。
示例 14:收集包含分布统计信息的目录统计信息
RUNSTATS ON TABLE db2admin.department WITH DISTRIBUTION AND INDEXES ALL
将 num_freqvalues parameter 设置为 10, num_quantiles parameter 设置为 20,因为在命令行上没有指定 num_freqvalues 和 num_quantiles 参数。
示例 15:仅收集表上的目录统计信息,其中使用指定的 num_freqvalues 以及从数据库配置设置选择 num_quantiles 收集所有列上的分布统计信息
RUNSTATS ON TABLE db2admin.department WITH DISTRIBUTION DEFAULT
NUM_FREQVALUES 40
将 num_freqvalues 参数设置为 40, num_quantiles 参数设置为 20。
示例 16:收集表上的目录统计信息,包含列 deptno 和 deptname 上的分布统计信息。单独为 deptname 列设置分布统计信息的范围,而 deptno 列使用公共的默认值。并且还为两个索引 IDX1 和 IDX2 收集目录统计信息。
RUNSTATS ON TABLE db2admin.department WITH DISTRIBUTION ON COLUMNS
(deptno, deptname NUM_FREQVALUES 50 NUM_QUANTILES 100) DEFAULT
NUM_FREQVALUES 5 NUM_QUANTILES 10 AND INDEXES db2admin.IDX1, db2admin.IDX2
对于 deptname 列, num_freqvalues 是 50, num_quantiles 是 100。
对于 deptno 列, num_freqvalues 5, num_quantiles 是 10。
示例 17:收集所有索引上的目录统计信息,包含列 deptname 上的分布统计信息。未列出的列上的分布统计信息将被清除。
RUNSTATS ON TABLE db2admin.department WITH DISTRIBUTION ON COLUMNS
(deptname NUM_FREQVALUES 20 NUM_QUANTILES 40)
AND INDEXES ALL
对于 deptname 列, num_freqvalues 是 20, num_quantiles 是 40。
示例 18:收集所有索引以及列 deptno 和 deptname 上的目录统计信息。deptno 列的 num_freqvalues 和 num_quantiles 值将从默认值中获得。
RUNSTATS ON TABLE db2admin.department WITH DISTRIBUTION ON COLUMNS
(deptno, deptname NUM_FREQVALUES 20 NUM_QUANTILES 40) DEFAULT
NUM_FREQVALUES 0 NUM_QUANTILES 0 AND INDEXES ALL
对于 deptname 列, num_freqvalues 是 20, num_quantiles 是 40。
对于 deptno 列, num_freqvalues 是 0, num_quantiles 是 0。
其他所有列不包含任何统计信息。
回页首
包含列组统计信息的 RUNSTATS
列组(Column Group)统计信息将获得一组列的不同值组合的数目。通常,DB2 优化器可用的基本统计信息不检测数据相关性。列组的使用将给多个谓词的联合选择提供更准确的估计。列组统计信息假设数据是均匀分布的;但还无法获得列组上的分布统计信息。
较于列组的基数,单个列的基数(cardinality)的乘积将获得更好的相关性估计。
下列例子说明了如何使用 RUNSTATS 收集捕获了列组信息的目录统计信息:
示例 19:收集捕获了列组的目录统计信息
RUNSTATS ON TABLE db2admin.department ON COLUMNS ((deptno, deptname),
deptname, mrgno, (admrdept, location))
本例中,总共有两个列组:(deptno, deptname) 和 (admrdept, location)。
回页首
包含 LIKE STATISTICS 的 RUNSTATS
当在 RUNSTATS 中指定 LIKE STATISTICS 子句时,将收集附加的列统计信息。这些统计信息存储在 SYSIBM.SYSCOLUMNS 表里的 SUB_COUNT 和 SUB_DELIM_LENGTH 列中。它们仅针对字符串列进行收集,查询优化器用它们来提高“column LIKE ‘%abc‘”和“column LIKE ‘%abc%‘”类型谓词的选择性估计。
下列例子说明了如何使用 RUNSTATS 收集捕获了 LIKE 统计信息的目录统计信息:
示例 20:收集所有列上的目录统计信息并指定 VARCHAR 列上的 LIKE 统计信息
RUNSTATS ON TABLE db2admin.department ON ALL COLUMNS and COLUMNS (deptname LIKE STATISTICS)
回页首
包含统计信息配置文件的 RUNSTATS
现在,可以在 DB2 V8.2 中为 RUNSTATS 建立一个统计信息的配置文件。统计信息配置文件是指一组选项,它预先定义了特定表上将要收集的统计信息。
当将命令参数“SET PROFILE”添加到 RUNSTATS 命令时,将在表描述符和系统目录中注册或存储统计信息配置文件。若要更新该统计信息配置文件,则可以使用命令参数“UPDATE PROFILE”。
没有删除配置文件的选项。
下列例子展示了如何使用这项功能:
示例 21:只注册一个统计信息配置文件,不收集目录统计信息
RUNSTATS ON TABLE db2admin.department AND INDEXES ALL SET PROFILE ONLY
RUNSTATS 中的子句“SET PROFILE ONLY”不收集统计信息。
示例 22:注册一个统计信息配置文件,并执行所存储统计信息配置文件的 RUNSTATS 命令选项来收集目录统计信息
RUNSTATS ON TABLE db2admin.department AND INDEXES ALL SET PROFILE
示例 23:仅修改现有的统计信息配置文件,不收集任何目录统计信息
RUNSTATS ON TABLE db2admin.department WITH DISTRIBUTION AND INDEXES ALL UPDATE PROFILE ONLY
示例 24:修改现有的统计信息配置文件,并执行已更新的统计信息配置文件的 RUNSTATS 命令选项来收集目录统计信息
RUNSTATS ON TABLE db2admin.department WITH DISTRIBUTION AND INDEXES ALL UPDATE PROFILE
示例 25:根据前面已注册的统计信息配置文件来查询 RUNSTATS 选项
SELECT STATISTICS_PROFILE FROM SYSIBM.SYSTABLES WHERE NAME = ‘DEPARTMENT‘ AND CREATOR = ‘DB2ADMIN‘
示例 26:使用前面已注册的统计信息配置文件收集目录统计信息
RUNSTATS ON TABLE db2admin.department USE PROFILE
回页首
带有抽样的 RUNSTATS
随着数据库快速不断地增长,通过访问所有数据收集统计信息的能力可能会受到固定的批量窗口、内存和 CPU 约束的阻碍。
目前,要运行表上的 RUNSTATS,就要执行全表扫描。通过数据抽样,只需扫描数据的一个子集即可。
如果一个查询试图预计总的趋势和模式,且某一误差域(margin of error)内的近似答案足以监测这些趋势和模式,那么数据抽样或许是比全表扫描更好的选择。
在 DB2 V8.1 中,引入了 SAMPLED DETAILED 子句,允许通过抽样计算详细的索引统计信息。该子句的使用将减少为获得详细索引统计信息而执行的后台计算量和所需的时间,但在大多数情况下,都会使数据足够的精确。
以下是一些关于该子句的使用的例子:
示例 27:收集两个索引上的详细目录统计信息,但对每个索引条目使用抽样来代替执行详细的计算
RUNSTATS ON TABLE db2admin.department AND SAMPLED DETAILED INDEXES ALL
示例 28:收集索引上的详细抽样统计信息和表的分布统计信息
RUNSTATS ON TABLE db2admin.department WITH DISTRIBUTION ON KEY
COLUMNS AND SAMPLED DETAILED INDEXES ALL
在 DB2 V8.2 中,提供了对表数据进行抽样的两种新方法:行级的贝努里(Bernoulli)抽样和系统页级的抽样。
回页首
带有行级贝努里(Bernoulli)抽样的 RUNSTATS
行 级贝努里(Bernoulli)抽样利用 sargable(search + argument-able 谓词是一个可以由数据管理器来评估的谓词)谓词获得百分之 P 的表行样本,在样本中包含每一行的概率是 P/100,而不包含它的概率则是 1 - P/100。
例如,对于 10% 贝努里(Bernoulli)抽样,将会选择 10%(10/100)的行,而拒绝 90%(1-10/100)的行。在贝努里(Bernoulli)抽样中,每一页将会引发一次 I/O,因为要扫描该表。将生成一个随机数来确定是否选择一行(类似于以 P/100 的概率扔钱币)。即使每一页都发生一次 I/O,我们仍然节省了处理数据所需的 CPU 时间。
在行级贝努里(Bernoulli)抽样中,需要读取每一个数据页。然而,它仍然可以带来极大的性能提高,因 为 RUNSTATS 是 CPU 密集的。如果索引是可用的,那么就会改进抽样。如果数据是群集的,它还可以提供更准确的统计信息(所获得的样本更好地代表了整个表数据)。
回页首
带有系统页级抽样的 RUNSTATS
系 统页级抽样与行级抽样类似,除了抽样的对象是页面而不是行。以 P/100 的概率选择每一页,而以 1 - P/100 的概率拒绝页的选择。在所选中的每一页中,要选择所有的行。系统页级抽样优于全表扫描或贝努里(Bernoulli)抽样的地方是它节省了 I/O。
抽样页也是预取的,所以该方法将比行级贝努里(Bernoulli)抽样更快。与不进行抽样相比,页级抽样极大地提高了性能。
RUNSTATS repeatable 子句允许通过 RUNSTATS 语句生成相同的样本,只要表数据没有发生更改。为了指定该选项,用户还必须提供一个整数,以表示将用于生成样本的种子(seed)。通过使用相同的种子,可以生成相同的样本。
总之,统计信息的准确性取决于抽样率、数据倾斜(data skew)以及用于数据抽样的数据群集。
下面是一些使用贝努里(Bernoulli)行级和系统页级抽样的 RUNSTATS 例子:
示例 29:收集统计信息,包含 10% 行上的分布统计信息
RUNSTATS ON TABLE db2admin.department WITH DISTRIBUTION TABLESAMPLE BERNOULLI (10)
示例 30:为了控制收集统计信息的样本集,以及可以重复使用相同的样本集,需要使用下列语句:
RUNSTATS ON TABLE db2admin.department WITH DISTRIBUTION TABLESAMPLE
BERNOULLI (10) REPEATABLE (1024)
示例 31:收集 10% 的数据页上的索引统计信息和表统计信息。请注意,只对表数据页进行抽样,而不是索引页。本例中,10% 的表数据页用于表统计信息的收集,而对于索引统计信息,将使用所有的索引页。
RUNSTATS ON TABLE db2admin.department AND INDEXES ALL TABLESAMPLE SYSTEM (10)
回页首
收集目录统计信息的可供选择的方法
对于数据库中的所有表,收集统计信息的一个可供选择的方法就是发出一条 REORGCHK 命令,如下所示:
示例 32:使用 REORGCHK 收集所有表的目录统计信息
REORGCHK UPDATE STATISTICS ON TABLE ALL
reorgchk 命令的 update statistics 选项的作用类似于调用 RUNSTATS 例程来更新数据库中所有表的目录统计信息,但是所有列上的统计信息只能通过默认的 RUNSTATS 选项来收集。通过使用该命令,还可以收集单个表上或同一模式下一组表的统计信息。
示例 33:使用 REORGCHK 收集一个表的目录统计信息
REORGCHK UPDATE STATISTICS ON TABLE db2admin.department
示例 34:使用 REORGCHK 收集一个模式的目录统计信息
REORGCHK UPDATE STATISTICS ON SCHEMA systools
虽然该方法看上去是一种在多个表上收集目录统计信息的快速方法,但是仅仅当 REORGCHK 可以在合理的时间内完成执行时,该方法才是可取的。
在表的 LOAD REPLACE 期间以及索引的创建期间,也可以进行目录统计信息的收集。
在 UDB V8.2 中,为了在 LOAD 期间调用目录统计信息的收集,必须将选项“STATISTICS USE PROFILE”添加到 LOAD 控制语句中。选项“STATISTICS YES”仍然有用,但它现在已是过时的语法。若在表的 LOAD 之后在同一表上执行 RUNSTATS,那么在 LOAD 期间发出“STATISTICS USE PROFILE”的目的就是为了减少正常运行过程中占用的时间。在执行 load 之前,就必须创建统计信息配置文件,它现在允许指定与 RUNSTATS 命令中相同的统计信息选项。
示例 35:使用 LOAD 命令和 STATISTICS USE PROFILE 子句收集目录统计信息
LOAD FROM inputfile.del OF DEL REPLACE INTO db2admin.department STATISTICS USE PROFILE
大多数情况下,RUNSTATS 是在创建索引之后执行的。然而,在执行索引创建操作时,也能收集索引的统计信息。这将避免为了收集统计信息而进行的另一项索引扫描。下列例子说明了完成这项工作可以使用的一些选项:
示例 36:收集基本的索引目录统计信息:
CREATE INDEX db2admin.inx1 ON db2admin.department (deptno) COLLECT STATISTICS
示例 37:收集扩展的索引目录统计信息:
CREATE INDEX db2admin.inx2 ON db2admin.department (deptname) COLLECT DETAILED STATISTICS
示例 38:收集扩展的索引目录统计信息,指定使用抽样:
CREATE INDEX db2admin.inx3 ON db2admin.department (deptname) COLLECT SAMPLED DETAILED STATISTICS
回页首
包含授权和用户访问的 RUNSTATS
为了可以对一个表或索引收集统计信息,必须能够连接到包含该表和索引的数据库,并具有下列授权级别之一:
sysadm
sysctrl
sysmaint
dbadm
表上的 CONTROL 权限
当对一个表运行 RUNSTATS 时,有两种用户访问选项:允许读访问和允许写访问。
在 RUNSTATS 命令中的参数 ALLOW READ ACCESS 指定计算统计信息时,其他用户可以只读地访问该表。
在 RUNSTATS 命令中的参数 ALLOW WRITE ACCESS 指定计算统计信息时,其他用户可以读取或写入该表。如果该表在任何时刻都必须是可用的,那么应该使用该子句。
回页首
分区数据库中的 RUNSTATS
当 在一个分区数据库中发出 RUNSTATS 命令,并且一个表分区位于发出 RUNSTATS 的数据库分区中时,那么 RUNSTATS 将在该数据库分区上执行。如果表分区不在该数据库分区上,那么将请求发送给数据库分区组中持有该表分区的第一个数据库分区。然后,在该数据库分区上执行 RUNSTATS 命令。
RUNSTATS 不是在分区的数据库中并行运行的,但对一个分区确定信息,然后对所有分区推断出合适的估计值。有一个隐式的假设:每个表中的行是均匀分布在每个多分区数据库分区组中的所有分区上的。
下列 IBM 技术札记(technote)谈到了加载一个表时运行 RUNSTATS 可能碰到的问题。其解决方案就是确保在加载表之前,为该表定义一个分区键(partitioning key)。
IBM Technote # 1153232(2004-02-12):
“加载表之后,Runstats 将多分区实例上 syscat.tables 中的列 CARD 更新为零行。
摘要
如果加载某一给定表之后,其中一个分区的行数为零,并且将从该分区执行 runstats,那么该命令将更新 syscat. 表中的列 CARD,显示该表的行数为零。这只对多分区的实例有影响。
内容
runstats 的行为使其将使用运行它的分区上的数据来推测该表中的行数。例如,如果加载之后所有数据都在一个分区上,并从另一分区执行 runstats,那么该命令将更新 syscat.tables 来表示该表的行数为零。然而,如果是从保存所有数据的分区运行 runstats,那么它将更新 syscat.tables 来展示该表包含((该分区上的行数)x(分区数目))行。
为了避免 runstats 的行为默认行为,需要在加载表之前,为该表定义分区键(partitioning key)。分区键需要位于高度惟一的一列或一组列上,从而确保数据均匀分布在该表所定义的所有分区上。”
回页首
调整 STAT_HEAP_SZ 数据库配置参数
stat_heap_sz 或统计信息堆大小的数据库配置参数指定了使用 RUNSTATS 命令收集统计信息中所用堆的最大尺寸。它是在启动 RUNSTATS 实用程序时分配的,然后当它完成时释放。stat_heap_sz 是代理私有内存的一部分。因此,在收集分布统计信息时,最好增大 stat_heap_sz 参数,以便能将更多的列放入这个堆中。处理较宽的表也需要更多的内存。当执行包含 SAMPLED DETAILED 选项的 RUNSTATS 时,必须额外分配 2 MB 内存,以确保 RUNSTATS 能够成功运行。
回页首
减小 RUNSTATS 对系统性能影响的策略
您可以使用下列策略来帮助减小 RUNSTATS 对于系统的性能影响:
一次仅在少数表和索引上运行 RUNSTATS,在整组表中循环运行。
仅指定将收集其数据分布统计信息的那些列。仅指定那些谓词中所使用的列。
对于不同的表,在不同的分区上实现多个并发的 RUNSTATS。
仅在那些影响当前工作负载的关键表上执行 RUNSTATS。避免在不需要它的表上运行 RUNSTATS。
根据表中数据发生改变的速度,调整 RUNSTATS 的频率。
根据 RUNSTATS 在该表上完成运行的速度,调整 RUNSTATS 的频率和细节。
仅在系统活动量少的时候,安排执行 RUNSTATS。
调整(Throttle)RUNSTATS,以便最大程度地减少它对系统的需求。
仅在系统活动量少的时候安排执行 RUNSTATS,这是最大程度地减少系统影响的一个好方法。然而,对于一个 24 x 7 的系统,系统中可能没有可用的窗口或活动量少的时候。处理该情形的一种方法就是使用 RUNSTATS 的 throttling 选项。
throttling 选项将根据当前的数据库活动级别,来限制实用程序所占有的资源数量。UDB 中,在调整时,util_impact_lim 与 UTIL_IMPACT_PRIORITY 参数的交互确定了 RUNSTATS 的行为。UTIL_IMPACT_PRIORITY 关键字被用于诸如 RUNSTATS 的实用程序命令的子句中,而 util_impact_lim 则是一个实例配置参数。
util_impact_lim 参数是指允许所有已调整实用程序对于实例的工作负载产生影响的百分比。如果 util_impact_lim 是 100(默认值),则不用调整诸如 RUNSTATS 之类的实用程序调用。例如,如果将 util_impact_lim 设置为 10,那么已调整的 RUNSTATS 调用就被限定在消耗 10% 以下的工作负载。
UTIL_IMPACT_PRIORITY 关键字可充当一个开关,它指定 RUNSTATS 是否订阅调整策略。
示例 39:UTIL_IMPACT_PRIORITY 关键字的使用
RUNSTATS ON TABLE db2admin.department AND INDEXES ALL UTIL_IMPACT_PRIORITY 10
其中,10 是调整 RUNSTATS 的优先权或级别。
当 util_impact_lim 不是 100,而且用 UTIL_IMPACT_PRIORITY 调用 RUNSTATS 时,将会对该值进行调整。如果没有为 UTIL_IMPACT_PRIORITY 指定优先权,且 util_impact_lim 不是 100,那么 RUNSTATS 将使用默认的优先权 50,并将据此进行调整。如果在 RUNSTATS 命令中省略 UTIL_IMPACT_PRIORITY 关键字,那么可以不加调整地运行 RUNSTATS。如果指定了优先权,但是将 util_impact_limit 设置为 100,也可以不加调整地运行 RUNSTATS。如果将优先权设置为零,也能不加调整地运行 RUNSTATS。
当定义了 RUNSTATS 调整(throttling),并且该调整可操作时,RUNSTATS 实用程序预计将花费更长时间,但是对系统产生的影响会少一些。
回页首
RUNSTATS 的其他问题
已声明的全局临时表上的 RUNSTATS
可 以在已声明的全局临时表(DGTT)上发出 RUNSTATS 命令,但是结果的统计信息不存储在系统目录中,因为声明的临时表条目没有目录条目。这些统计信息存储在表示声明的临时表的目录信息的内存结构中。如果整个 查询经过时间中所节省的时间比完成 RUNSTATS 所增加的时间大得多,就建议发出 RUNSTATS。
可以在 SQL 例程(过程、UDF 和方法)中发出 RUNSTATS 命令吗?
下列 IBM 技术札记(technote)讨论了该问题:
IBM Technote # 1153051
“既不能从 SQL 例程(过程、UDF、方法)、SQL 动态复合语句发出 RUNSTATS 命令,也不能使用从 SQL 例程中发出的操作系统调用来发出该命令。如果需要发出 RUNSTATS 命令,那么可以直接从命令行处理器(Command Line Processor,CLP)发出它,或者通过使用 db2Runstats() API 函数(DB2 8.1 开始)从客户机应用程序或外部语言例程发出它,以及通过 LOAD 和 CREATE INDEX 语句发出该命令。”
可以创建一个名为“runstats”的 C 存储过程,调用 db2Runstats() API 函数。然后,可以使用 CALL 命令调用这个 C 存储过程。
如何通过调用级接口(CLI)或 Java 执行 RUNSTATS 来收集统计信息?
下列 IBM 技术札记回答了该问题:
IBM Technote # 1023788:
“DB2 管理 API(编程接口)sqlustat 可以用于从 DB2 应用程序发出 RUNSTATS,例如写入调用级接口的应用程序。DB2 Administrative API Reference 手册中描述了 sqlustat。”
回页首
DB2 自动统计信息收集
DB2 自动统计信息收集是在 DB2 UDB Version 8.2 中引入的。自动统计信息收集是完全自动表维护解决方案的一部分。其目标是允许 DB2 确定工作负载需要哪些统计信息,并定期在后台自动运行 RUNSTATS 实用程序,以便按需更新统计信息。
为了设置 SAMPLE 数据库自动进行统计信息收集,需要为自动维护开关设置数据库配置参数,如下所示:
db2 update db cfg for SAMPLE using AUTO_MAINT ON
db2 update db cfg for SAMPLE using AUTO_TBL_MAINT ON
db2 update db cfg for SAMPLE using AUTO_RUNSTATS ON
下图(只显示统计信息收集和配置选项)展示了统计信息收集和配置的自动维护命令的层次结构和相关性。在该结构中,可以在最高层次快速关闭自动维护参数 AUTO_MAINT,而不丢失较低层的配置设置,比如 AUTO_RUNSTATS。
图 1. 自动维护设置
如 果需要自动统计信息配置,那么可以打开参数 AUTO_STATS_PROF 和 AUTO_PROF_UPD。自动统计信息配置则通过确定何时和如何收集统计信息更进了一步。统计信息配置文件是自动生成的,自动统计信息收集过程将用它 来调度 RUNSTATS。可以用内部算法来比较新收集的统计信息与已保存的一组统计信息,并基于某些触发条件发出包含抽样的 RUNSTATS。
当启用自动统计信息配置时,数据库活动的有关信息被收集并存储在查询反馈仓库中。然后,基于查询反馈仓库中的数据生成统计配置文件。
为了允许自动生成统计信息配置文件,需要设置两个数据库配置参数:
db2 update db cfg for SAMPLE using AUTO_STATS_PROF ON
打开该参数将启动查询反馈数据的收集。
db2 update db cfg for SAMPLE using AUTO_PROF_UPD ON
打开该参数,指定使用分析查询反馈数据的 DB2 中的建议来更新 RUNSTATS 配置文件。
在触发自动统计信息配置之前,必须通过运行 SYSINSTALLOBJECTS 存储过程创建查询反馈仓库。
按照下列方式调用该存储过程:
call SYSINSTALLOBJECTS ( toolname , action , tablespacename , schemaname )
其中,toolname 是“ASP”或“AUTO STATS PROFILING”,对于 action,“C”表示创建,“D”表示删除。
目前,不使用参数 schemaname。
例如,要创建反馈仓库,需要运行下列存储过程:
call SYSINSTALLOBJECTS (‘ASP‘, ‘C‘, ‘USERSPACE1‘, ‘‘)
该过程将创建下列表、存储建议以及与查询执行过程中碰到的谓词有关的信息:
SYSTOOLS.OPT_FEEDBACK_QUERY
SYSTOOLS.OPT_FEEDBACK_PREDICATE
SYSTOOLS.OPT_FEEDBACK_PREDICATE_COLUMN
SYSTOOLS.OPT_FEEDBACK_RANKING
SYSTOOLS.OPT_FEEDBACK_RANKING_COLUMN
当禁用 AUTO_PROF_UPD 参数时,可以将建议存储在 SYSTOOLS.OPT_FEEDBACK_RANKING 表中。然后,当手动更新 RUNSTATS 配置文件时,就可以查看该表中所存储的建议。
DB2 自动统计信息收集和配置生成只能在 DB2 串行模式下启用;它们在联邦的、SMP 和 MPP 环境中是不可用的。
回页首
结束语
理 解并正确使用 RUNSTATS 是维护高性能数据库的关键之一。本文讨论了 RUNSTATS 的重要性,并解释了许多使 RUNSTATS 更有用的可用选项,其中包括 V8.2 中的一些新选项,通过允许建立指定需要为每个表收集哪些统计信息的配置文件,这些新选项简化了管理。我所展示的示例将使您易于使用 RUNSTATS 获得最佳的数据库性能。