目录
11.2.5.包含LIKE STATISTICS的RUNSTATS
11.1 统计信息更新
统计信息是DB2收集的关于数据库中各个数据对象状态的信息,这些信息在收集好以后被保存在数据库系统编目表中,当应用程序或SQL语句对数据进行访问的时候,优化器需要根据这些统计信息来生成成本最低的执行计划。只有准确的统计信息才能让DB2优化器产生最优的执行计划,进而提高数据访问效率。如果数据库中的统计信息是过时的或者没有相关的统计信息,那么数据的高效访问就无从谈起。所以统计信息的准确与否就显得非常重要。
11.1.1.统计信息的重要性
DB2不会在每次数据库添加、删除、更新数据后都实时更新数据库统计信息,这是因为过于频繁的更新统计信息有可能造成系统性能的巨大开销,此外,如果改变的数据量有限,那么有可能统计信息的一些微误差不会造成DB2选择成本高昂的访问路径。
更新统计信息有2种方式:自动、手动。
自动方式:打开数据库参数AUTO_RUNSTATS即可开启自动统计信息收集方式,每2个小时触发一次。
手动方式:当用户对表做了大量的数据更新后,可以考虑在表和索引上执行RUNSTATS命令来确保系统目录表中的统计信息是最新的。
成功执行RUNSTATS命令之后,静态SQL查询并不会使用最新的数据库统计信息,这是因为静态SQL的访问策略在之前执行BIND时就已经确定,而当时使用的统计信息有可能与现在的并不一致,此时就需要重新绑定使用静态SQL的应用程序,这样查询优化器就可以根据统计信息来选择获取数据的最佳访问策略。
对于使用动态SQL的应用程序而言,没必要进行重新绑定,因为动态SQL语句的访问策略是根据统计信息在运行时动态生成的。
如何更新统计信息?
①使用RUNSTATS命令:run statistics
②使用带有指定的统计信息收集选项的LOAD
③对针对一组预先定义的系统目录视图进行操作的SQL UPDATE语句进行编译
④使用reorgchk update statistics命令
⑤如果不完全知道所有表名或表名太多而无法对每张表逐个更新策略时:db2 reorgchk update statistics on table all
注意:
①在批量数据加载后要运行RUNSTATS命令
②如果知道表名且想避免对大量表执行RUNSTATS命令,那么一次对一张表进行RUNSTATS更为可取,毕竟对大量表进行RUNSTATS会花费很长的时间:db2 -v runstats on table tabschema.tabname and indexes all,该命令会收集该表及其所有索引的统计信息。
如何查看是否执行了RUNSTATS命令?
可以查询系统目录表中的以下列,确定是否在表、索引上执行了RUNSTATS命令:
①如果对于某个表,SYSCAT.TABLES视图的STATS_TIME列显示的值为NULL,那么这表示没有对该表执行RUNSTATS命令;
②如果对于某个索引,SYSCAT.INDEXES视图的STATS_TIME列显示的值为NULL,那么这表示还没有对该索引执行RUNSTATS命令;
db2 -v “select tbname,nleaf,nlevels,stats_time from syscat.indexes” db2 -v “select tbname,nleaf,nlevels,stats_time from syscat.tables” |
在表上执行RUNSTATS命令时,可以有2种用户访问选项:允许读访问ALLOW READ ACCESS、允许写访问ALLOW WRITE ACCESS。
如果是RUNSTATS + ALLOW READ ACCESS时,其他用户只能以只读的方式访问该表,这个选项会影响应用的并行性能,因为任何想要更改表的操作这个时候都会处于等待状态,为了提高速度,在使用ALLOW READ ACCESS时添加tablesample选项,该选项只收集表的部分采样数据而不是所有数据,因此如果合理选择采用数据的大小,那么就可以在确保统计信息一致性的情况下,加快runstats的速度;
如果是RUNSTATS + ALLOW WRITE ACCESS时,其他用户则可以读写该表,默认情况下RUNSTATS使用的就是ALLOW WRITE ACCESS选项;
注意:V9.7中的indexes视图与tables视图差别很大,建议用户自己去select *确认下;
分区数据库上的RUNSTATS
在分区数据库中,只需要在其中一个分区上发出RUNSTATS就可以对所有分区上的数据进行统计信息更新。
在DB2 V9.5之前,挡在分区数据库上执行RUNSTATS命令,并且表分区位于发出RUNSTATS的数据库分区中时,RUNSTATS将在该数据库分区上执行。如果表分区不在该数据库分区上,那么将请求发给数据库分区组中持有该表分区的第一个数据库分区,然后在该数据库分区上执行RUNSTATS命令。
RUNSTATS对分区收集统计信息时,有个隐含假设:每个表中的行均匀分布在每个多分区数据库分区组中的所有分区上。
当发生下列情况时,使用RUNSTATS命令来收集统计信息:
(1)当向表装入数据并创建了新的索引时
(2)当用REORG命令重新组织表、索引时
(3)当数据库中10%-20%的表、同一个表中10%-20%的索引发生更新、删除、插入操作时
(4)在绑定对性能要求很高的应用程序之前
(5)当希望对新、旧的统计信息进行比较时,定期进行统计使得能够在早期阶段发现性能问题
(6)当预存取prefetch size大小发生变化时
(7)当在表中创建新的索引时,如果自从上次在表中运行RUNSTATS以来尚未修改表,那么只需要对新的索引执行RUNSTATS
(8)使用RUNSTATS命令来收集关于XML列的统计信息
如果没有足够的时间一次性收集全部的统计信息,则可以运行RUNSTATS每次仅更新几个表、几个索引、统计信息视图的统计信息,并轮流完成该组对象。
如果对选择性部分更新运行RUNSTATS期间,由于表上的活动而产生了不一致性,则在查询优化期间将发出警告信息。
要确保索引统计信息和数据表同步,执行RUNSTATS来同时收集表、索引的统计信息。索引统计信息保留自从上次运行RUNSTATS以来收集的大部分表和列的统计信息,如果自上次收集该表的统计信息以来已经对该表进行了大量的修改,那么就只收集该表的索引统计信息会使得2组统计信息不能再所有节点上都同步。
鉴于RUNSTATS会对性能产生负面影响,RUNSTATS命令现在支持优先级选项,在执行较高级别的数据库活动期间,可以使用优先级选项来限制执行RUNSTATS的性能影响,可以采用下面技巧来提高RUNSTATS的效率以及已收集的统计信息的准确性:
(1)仅仅对用来连接表的列、where、group by、查询子句中的列收集统计信息,如果这些列建立了索引,则可以用RUNSTATS命令的ONLY ON KEY COLUMNS子句来指定列;
(2)为特定表、表中特定列定制num_freqvalues、num_quantiles的值;
(3)使用SAMPLED DETAILED子句通过抽样计算详细的索引统计信息,来减少为获得详细索引统计信息而执行的后台计算量,进而减少收集统计信息所需的时间,并在大多数情况下产生足够的精度;
(4)当创建已装载数据的表的索引时,添加COLLECT STATISTICS子句来在创建索引时创建统计信息;
(5)当添加/删除大量数据,或者更新收集了统计信息的列中的数据时,需要再次执行RUNSTATS命令来更新统计信息;
(6)在DB2 V9.5之前,因为RUNSTATS仅仅收集单个数据库分区的统计信息,所以如果数据不是在所有数据库分区中一致分布的话,那么统计信息将不太准确,可以在执行RUNSTATS之前使用REDISTRIBUTE DATABASE PARTITION GROUP命令先让各个数据库分区之间重新发布数据,确保数据分发的一致性分布;
完成每一条RUNSTATS语句之后,都应该执行显示的COMMIT命令,COMMIT将释放锁,并避免在收集多个表的统计信息时填满日志。
用RUNSTATS收集统计信息之后,使用BIND或者REBIND命令重新绑定包含了静态SQL的应用程序包,db2rbind命令可用于重新绑定数据库中所有应用程序包。使用FLUSH PACKAGE命令删除程序包缓存器package cache中当前所有缓存的动态SQL语句db2 flush package cache dynamic并强制隐式地编译一下请求。
11.1.2.减小RUNSTATS对系统性能影响的策略
①调整stat_heap_sz数据库配置参数
统计信息堆stat_heap_sz指定了使用RUNSTATS命令收集统计信息中所用内存堆的最大值,在启动RUNSTATS命令时分配的,然后在命令完成时释放,因此在收集统计信息时,最好增大stat_heap_sz参数,从而将更多的统计信息放入到这个堆中,当执行包含SAMPLED DETAILED选项的RUNSTATS命令时,将额外多占用2M的统计信息堆空间,因此必须分配更多内存来确保RUNSTATS命令能够更快完成。
②减小RUNSTATS对系统性能影响的策略
(1)一次仅在少数表和索引上运行RUNSTATS,在整组表中循环运行;
(2)仅指定将收集数据分布统计信息的那些列,仅指定那些谓词中使用的列;
(3)对于不同的表,在不同的分区上执行多个并发的RUNSTATS命令;
(4)仅在那些迫切需要提高当前工作负载性能的关键表上执行RUNSTATS命令,避免在不需要它的表上运行RUNSTATS命令;
(5)根据表中数据发生改变的速度,调整RUNSTATS命令定期执行的频率;
(6)根据RUNSTATS命令在表上完成运行的速度,调整RUNSTATS的频率和采样数据的多少;
(7)调整RUNSTATS,以便最大程度的减少其对系统资源的需求;
throttle与RUNSTATS
仅在系统活动量少的时候安排执行RUNSTATS命令,从而最大程度减少对系统的影响,但对于24 * 7的系统而言,系统中压根没有可用的时间窗口来安排执行RUNSTATS,此刻需要使用RUNSTATS的throttling选项来应对这种情况。
throttling选项将根据当前的数据库活动级别,限制RUNSTATS命令占有的资源数量。util_impact_lim与util_impact_priority参数配合使用确定了RUNSTATS命令的行为;
util_impact_lim:实例配置参数,指允许所有运行的程序对于实例的工作负载产生影响的百分比,举个列子util_impact_lim默认值为10,则表示正在运行的RUNSTATS命令就被限定消耗10%以下的工作负载;
util_impact_priority:是RUNSTATS的子选项,指定RUNSTATS命令是否使用util_impact_lim这种调整策略;
这2个参数组合场景如下:
util_impact_lim != 100 且使用util_impact_priority明确指定具体的优先权时 | 将会调整util_impact_priority的参数值 |
util_impact_lim != 100 且使用util_impact_priority,但没有明确指定具体的优先权时 | RUNSTATS将使用默认的优先权50,并将据此进行调整 |
没有使用util_impact_priority | 不会对正在运行的RUNSTATS命令做资源调整 |
util_impact_lim = 100 且使用util_impact_priority明确指定具体的优先权时 | 可以不对正在运行的RUNSTATS命令做资源调整 |
util_impact_priority = 0 | 可以不对正在运行的RUNSTATS命令做资源调整 |
当定义了RUNSTATS的util_impact_priority时并且该调整优先级可操作时,RUNSTATS运行时间更长,但对系统影响会更少。
11.1.3.DB2自动统计信息收集
DB2自动统计信息收集是在DB2 UDB Version 8.2中引入的。这里需要厘清一个概念:配置的自动化、统计信息收集的自动化层级关系,具体看下图:
层级从高往下依次排序为: |
自动维护(AUTO_MAINT) |
自动表维护(AUTO_TBL_MAINT) |
自动runstats(AUTO_RUNSTATS) |
自动配置统计信息(AUTO_STATS_PROF) |
自动配置更新(AUTO_PROF_UPD) |
如果需要自动化统计信息配置,则需要分别开启AUTO_STATS_PROF、AUTO_PROF_UPD参数,通过对自动化统计信息配置来确定何时、如何收集统计信息,而统计信息配置文件则是自动生成的,自动统计信息收集过程就是用该配置文件调度RUNSTATS的过程。
当启用自动统计信息配置时,数据库活动的有关信息被收集、存储在查询反馈库中,然后基于查询反馈库中的数据来生成统计配置文件。
为了允许SAMPLE数据库自动生成统计信息配置文件,则需要设置这2个数据库配置参数:
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表示删除
举个例子:要创建反馈库,需要运行下列存储过程:
call SYSINSTALLOBJECTS(‘ASP’,’C’,’USERSPACE1’,’’) |
11.2.统计信息更新案例分析
11.2.1.RUNSTATS更新示例
(1)收集所有列上的统计信息:
RUNSTATS ON TABLE db2admin.department ON ALL COLUMNS; 且该语句等价于:RUNSTATS ON TABLE db2admin.department;
在RUNSTATS语法中必须使用完全限定的表名schema.tabname、索引名schema.indname,同时即可以在所有列、指定列、列组上执行RUNSTATS,如果没有指定特定列的子句,则系统会使用默认的ON ALL COLUMNS子句;
(2)收集单个列上的数据库统计信息:
RUNSTATS ON TABLE db2admin.department ON COLUMNS(deptno,deptname);
如果deptno和deptname没有索引,则这条命令不会收集任何列的统计信息;
(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;
11.2.2.收集分布式统计信息
当确定表中数据分布不均匀时,可以运行包含WITH DISTRIBUTION子句的RUNSTATS命令。
系统目录表中的统计信息通常包含关于表中最高值、最低值的信息,而优化器会假设数据值是在两个端点值之间均匀分布的。然而,如果数据值彼此之间差异较大,或者群集在某些点上,或者碰到许多重复的数据值,这几种场景下优化器就无法选择最佳的访问路径,除非收集了分布统计信息。
当使用WIHT DISTRIBUTION子句还可以帮助查询处理没有参数标记或主机变量的谓词,因为优化器仍然不知道运行时的值是有许多行,还是只有少数行。
(1)收集表、索引上的数据库统计信息,包括分布统计信息:
RUNSTATS ON TABLE db2admin.department WITH DISTRIBUTION AND INDEXES ALL;
(2)收集表的数据库统计信息、索引上的详细统计信息,包括分布统计信息:
RUNSTATS ON TABLE db2admin.department WITH DISTRIBUTION AND DETAILED INDEXES ALL;
(3)收集选定列中包含分布的数据库统计信息:
RUNSTATS ON TABLE db2admin.department WITH DISTRIBUTION ON COLUMNS(deptno,deptname);
(4)只收集表上的数据库统计信息,包含deptno和deptname的基本列统计信息、mgrno和admrdept上的分布统计信息:
RUNSTATS ON TABLE db2admin.department ON COLUMNS(deptno,deptname) WITH DISTRIBUTION ON COLUMNS(mgrno,admrdept);
(5)收集构成索引的所有列、两个非索引列中包含分布的数据库统计信息:
RUNSTATS ON TABLE db2admin.department WITH DISTRIBUTION ON KEY COLUMNS AND COLUMNS(location,admrdept);
11.2.3.包含频率和分位数统计信息的RUNSTATS
在执行包含WITH DISTRIBUTION子句的RUNSTATS时,会根据RUNSTATS命令中给定的选项,来选择一组频率frequency、分位数quantile的统计信息。
RUNSTATS收集2种类型的数据分布统计信息:频率统计信息、分位数统计信息。
频率统计信息frequency的默认值由num_freqvalues数据库配置参数控制的,该值提供了重复最多的列和数据值的信息,默认值是10,如果该参数设置为0,则将不会保留任何频率值的统计信息。
分位数统计信息quantile的默认值由num_quantiles数据库配置参数控制,该值提供了数据值对于其他值而言是如何分布的有关信息,num_quantiles数据库配置参数指定应将列数据值分成的组数,默认值是20,如果将该参数设置为1或者0,将不会收集任何分位数统计信息。
如果用户没有在RUNSTATS命令的列、表上指定num_freqvalues和num_quantiles,则这2个参数读取数据库配置的数值。
11.2.4.包含列组统计信息的RUNSTATS
列组统计信息将获取一组列的不同值组合的数目,列组的使用将给多个谓词的联合选择提供更准确的估计,由于列组统计信息是假设数据均匀分布的,但还无法获得列组上的分布统计信息。
RUNSTATS ON TABLE db2admin.department ON COLUMNS((deptno,deptname),deptname,mrgno,(admrdept,location));
11.2.5.包含LIKE STATISTICS的RUNSTATS
当在RUNSTATS使用LIKE STATISTICS选项时,将收集附加的列统计信息。而这些统计信息存储在sysibm.syscolumns表的sub_count和sub_delim_length列中。
此时他们仅仅针对字符串列进行收集,查询优化器用收集的信息来提高column like ‘%abc%’和column like ‘%abc’类型谓词的选择性估计,例如:
RUNSTATS ON TABLE db2admin.department ON ALL COLUMNS AND COLUMNS(deptname LIKE STATISTICS);
11.2.6.包含统计信息配置文件的RUNSTATS
从DB2 V8.2开始,可以为RUNSTATS建立统计信息的配置文件。该配置文件是指一组选项,来预先定义特定表上将要收集的统计信息。
通过SET PROFILE添加到RUNSTATS命令时,将在表描述符、系统目录中注册或者存储统计信息配置文件。如果要更新统计信息配置文件,可以使用命令参数UPDATE PROFILE。
只注册统计信息配置文件,不收集数据库统计信息:
RUNSTATS ON TABLE db2admin.department AND INDEXES ALL SET PROFILE ONLY;
注册统计信息配置文件,并执行所存储统计信息配置文件的RUNSTATS命令选项来收集目录统计信息:
RUNSTATS ON TABLE db2admin.department AND INDEXES ALL SET PROFILE;
仅修改现有的统计信息配置文件,不收集任何数据库统计信息:
RUNSTATS ON TABLE db2admin.department WITH DISTRIBUTION AND INDEXES ALL UPDATE PROFILE ONLY;
修改现有的统计信息配置文件,并执行已更新的统计信息配置文件的RUNSTATS命令选项来收集数据库统计信息:
RUNSTATS ON TABLE db2admin.department WITH DISTRIBUTION AND INDEXES ALL UPDATE PROFILE;
根据前面已经注册的统计信息配置文件来查询RUNSTATS选项:
Select * from sysibm.systables;
使用前面已经注册的统计信息配置文件来收集数据库统计信息:
RUNSTATS ON TABLE db2admin.department USE PROFILE;
11.2.7.带有抽样的RUNSTATS
通过抽样,只扫描表的数据子集来收集数据库统计信息。从DB2 V8.1开始,引入了SAMPLED DETAILED子句,允许通过抽样计算详细的索引统计信息。该子句将减少为获得详细索引统计信息而执行的后台计算量和所需的时间,但在大多数情况下,都会让数据足够精确。
例如,收集2个索引上的详细数据库统计信息,但对每个索引条目使用抽样来取代执行详细的计算:
RUNSTATS ON TABLE db2admin.department AND SAMPLED DETAILED INDEXES ALL;
收集索引上的详细抽样统计信息和表的分布统计信息:
RUNSTATS ON TABLE db2admin.department WITH DISTRIBUTION ON KEY COLUMNS AND SAMPLED DETAILED INDEXES ALL;
11.2.8.带有系统页级抽样的RUNSTATS
系统页级抽样与行级抽样类似,只不过抽样对象是页面,而不是行。RUNSTATS repeatable子句允许通过RUNSTATS语句来生成相同的样本,只要表数据没有发生更改。
11.2.9.收集统计信息的其他可供选择的方法
①使用REORGCHK来收集所有表的数据库统计信息:
REORGCHK UPDATE STATISTICS ON TABLE ALL;
②使用REORGCHK收集表的数据库统计信息:
REORGCHK UPDATE STATISTICS ON TABLE db2admin.department;
③使用REORGCHK收集模式的数据库统计信息:
REORGCHK UPDATE STATISTICS ON SCHEMA systools;
④收集基本的索引数据库统计信息:
CREATE INDEX db2admin.inx1 ON db2admin.department(deptno) COLLECT STATISTICS;
⑤收集扩展的索引数据库统计信息:
CREATE INDEX db2admin.inx1 ON db2admin.department(deptno) COLLECT DETAILED STATISTICS;
⑥收集扩展的索引数据库统计信息,指定使用抽样:
CREATE INDEX db2admin.inx1 ON db2admin.department(deptno) COLLECT SAMPLED DETAILED STATISTICS;
11.3.碎片整理
随着数据被不断删除、插入、更新,数据页和索引页逐渐变得越来越零散,数据页和索引页的物理存储顺序不再匹配其逻辑顺序,数据和索引结构的层次会变得过大,从而导致数据页跨越在多个页上和索引页的预读取变得效率低下,因此,根据数据更新的频率需要适当重新组织表和索引。
11.3.1.表重组REORG
对表数据进行大量更改之后,逻辑上连续的数据可能会分散存储在很多个不连续的物理数据页中,因此数据库管理器必须执行更多的读操作来访问数据,同样的,某个表删除大量行后,由于表的高水位标记并不会发生变化,因此对该表做全表扫描时就会做很多不必要的IO操作。这几种情况下,就可以考虑重组表来回收浪费的空间、对数据进行重组,并且既可以重组系统目录表,还可以重组数据库表。
11.3.1.1重组表的方法
DB2 V8之后有2种表重组方法:脱机REORG、联机REORG;REORG命令指定了INPLACE选项则运行联机重组,未指定此项则运行脱机REORG;
REORG | 优点 | 缺点 |
脱机REORG | ①速度最快,尤其在不需要重组LOB/LONG数据时; ②完成时精确的维护了表和索引的集群; ③重组表后立即重建索引,不需要单独的步骤来重建索引; ④可以在临时表空间中构件影子副本,减少了包含目标表或索引的表空间的空间大小; ⑤允许指定并使用集群索引之外的索引来重新维护数据的集群,而联机重组在集群索引时必须使用现有的集群索引; | ①表访问受到限制,只有在重组排序、构建阶段才允许应用程序对表进行只读访问; ②由于使用影子部分的方法,因此需要较大空间; ③与联机REORG相比,脱机REORG对REORG过程的控制较少,不能在暂停后重新启动脱机重组; |
联机REORG | ①允许应用程序在REORG期间继续对表进行完全访问; ②对REORG过程具有更多控制:该过程在后台异步运行,并且可以使其暂停、继续、终止; ③在发生故障时可以恢复重组过程; ④由于采用递增方式处理表,需要较少的空间; | ①可能产生非最佳数据集群或者非最佳索引集群,这取决于REORG期间访问表的事务类型; ②重组开始时重组的页可能更新次数更多,从而比重组过程中稍后重组的表具有更多的碎片; ③速度比脱机重组要慢; ④联机重组是可恢复的过程,但这会导致日志记录空间要求提高; ⑤将维护索引而不是重建索引,因此以后可能需要额外单独的重组索引; |
11.3.1.2.监视表重组的进度
监视方式 | 说明 | 命令 |
历史记录文件 | 有关表重组当前进度信息,会写入数据库活动的历史记录文件中,历史记录文件中包含每个重组事件的记录,要查看此文件,执行db2 list history来打开包含所重组表的数据库;
| db2 list history |
表快照 | 使用表快照来监视表重组的进度,不管系统如何设置“数据库监视器表”开关,系统都会记录表重组监视数据 | db2 get snapshot for table on XXX表名 |
11.3.1.3.以脱机方式重组表
对表执行reorg table:
db2 reorg table test.employee
要使用临时表空间mytemp重组表:
db2 reorg table test.employee use mytemp
要重组表并根据索引myindex对行进行重新排序:
db2 reorg table test.employee index myindex
要使用SQL调用语句来重组表,使用ADMIN_CMD发出reorg-table命令:
call sysproc.admin_cmd(‘reorg table employee index myindex’)
11.3.1.4.脱机表重组的恢复
分:重组替换之前崩溃 与 替换阶段崩溃场景分别讨论;
在重组替换开始之前,脱机表重组是一个完全成功或者完全失败的过程。如果系统在排序或者构建阶段就崩溃,那么重组表操作将回滚,并且不会在崩溃恢复时自动重新进行reorg操作,而是必须在崩溃恢复后人工重新发出reorg table命令;
如果系统在进入替换阶段后才崩溃,那么重组表操作必须完成。这是因为已完成所有重组表工作后,原始表可能不再可用。在崩溃恢复期间,需要已重组对象的临时文件,而不是用于排序的临时表空间。恢复操作将完全重新开始替换阶段,并且需要恢复副本对象中的所有数据。在这种情况下,SMS表空间与DMS表空间之间有如下区别:必须将SMS对象从一个对象复制到另一个对象,而在DMS表空间中,如果重组在相同表空间中进行,那么仅指向刚刚重组的对象并废弃原始表。将不重建索引,但在崩溃恢复期间会将索引标记为无效。数据库将根据一般规则确定重建索引的时间:在数据库重新启动时或第一次访问索引时(可以通过设置DBM配置参数INDEXREC来制定索引重新创建时间和索引重新构建的时间,默认是RESTART)。
索引重建阶段出现崩溃表示我们已经拥有新对象,因此不重新执行任何操作。如上所述,将不重建索引,但在崩溃恢复期间会将索引标记为无效。数据库将根据一般规则确定重建索引的时间:在数据库重新启动时或第一次访问索引时。
11.3.1.5.提高脱机表重组的性能
脱机表重组的性能在很大程度上由数据库环境的特征决定的。
事实上,以NO ACCESS方式运行的重组表操作与以ALLOW READ ACCESS方式运行的重组表操作在性能方面没有任何差别,唯一区别在于:对于READ ACCESS方式,DB2在替换表之前升级对该表的锁定,因此程序可能必须等到现有扫描完成并释放其锁定后才能获得相应的锁,在这2种方式下,表在重组表操作的索引重建阶段不可用。
11.3.1.6.提高重组性能的技巧
如果表空间中有足够的空间,那么对原始表、表的已重组副本使用相同的表空间,而不使用临时表空间。节省从临时表空间中复制表所用的时间:
①考虑在重组表之前删除不必要的索引,以便在重组表操作期间维护较少的索引;
②确保正确设置了已重组的表所在表空间的预取大小;
③启用了intra_parallel,以便使用并行处理完成索引重建;
④调整sortheap、sheapthres参数来控制排序空间,因为每个处理器都将执行私有排序,所以sheapthres至少为sortheap * CPU处理器个数的值;
⑤通过调整页清除程序的数目,确保尽快从缓冲池中清除脏索引页;
11.3.1.7.联机表重组
联机表重组允许用户重组表的同时允许对该表进行完全访问。
联机表重组时,不是立即重组整个表,而是按顺序重组表的各个部分,不会将数据复制到临时表空间:在现有表对象中移动行以重新建立集群、回收可用空间、消除溢出行;
11.3.1.8.联机表重组期间创建的文件
联机表重组期间,将为每个数据库分区创建.OLR状态文件,文件名是xxxxyyy.OLR的二进制文件,其中xxxx是池标识,yyyy是十六进制的对象标识,该文件包含从暂停状态继续联机重组所需的信息。
11.3.1.9.恢复失败的联机表重组
如果运行时出现故障,那么联机表重组将暂停并进行回滚。
如果系统宕机,那么在重新启动时,将开始进行崩溃恢复,并且会暂停并回滚重组,稍后可以通过REORG TABLE并指定RESUME选项来继续重组;
11.3.1.10.暂停并重新启动联机表重组
要暂停联机表重组,可以使用带有PAUSE选项的REORG TABLE:
db2 reorg table homer.employee inplace pause
要重新启动已经暂停的联机表重组,可以使用带有RESUME选项的REORG TABLE命令:
db2 reorg table homer.employee inplace resume
11.3.1.12.监视表重组
可以通过get snapshot、snaptab_reorg视图、snap_get_tab_reorg表函数来获取有关表重组操作的状态信息;
例如:db2 get snapshot for tables on dbName
11.3.2.索引重组
通过删除、插入操作,在对表进行更新后,索引性能会降低,表现如下:
①索引叶子页分裂:叶子页被分裂之后,由于必须读取更多的叶子页才能访问存表页,因此IO操作成本增加;
②物理索引页顺序不再与这些页上的键顺序匹配,叶子页出现不良集群情况后,顺序预取操作的效率将降低,因此会导致更多的IO等待;
③形成的索引大于最有效的级别数,应重组索引;
如果在创建索引时指定了MINPCTUSED参数,则在删除某个键且可用空间小于指定的百分比时,数据库服务器会自动合并索引叶子页,该过程叫做联机索引整理碎片。
但要复原索引集群、复原可用空间、降低索引叶级别,使用下列一种方法:
①删除并重新创建索引;
②使用REORG INDEXES命令联机重组索引,此方法允许用户在重建表索引期间对表进行读、写操作,可以在生产环境下使用此方法;
③使用允许脱机重组表及其索引的选项,来运行REORG TABLE命令;
11.3.2.1.联机索引重组
当使用ALLOW WRITE ACCESS选项运行REORG INDEXES命令时,如果同时允许对指定的表进行读、写访问,那么会重建该表的所有索引。
进行重组时,对基表所做的任何将会影响到索引的更改都将记录在DB2日志中。另外,如果有任何内部缓冲区空间可供使用,那么还将这些更改存放在这样的内存空间中。
重组将处理所记录的更改以便在重建索引时与当前写活动保持同步更新。
内部内存缓冲区空间是根据需要从实用程序堆中分配的指定内存区域,用来存储对正在创建或重组的索引所做的更改。
在重组操作完成后,将释放所分配的内存,重组完成后,重建的索引可能不是最佳集群的索引,如果将索引指定PICTFREE,那么重组期间,每页上均会保留相应的百分比的空间;
对于分区表,支持对各个索引进行联机索引重组、清除,要对各个索引进行重组,需要指定索引名:reorg index indName for table tabName
使用CLEANUP ONLY选项对分区表的索引进行重组时,支持任何访问级别。如果未指定CLEANUP ONLY选项,那么默认访问级别ALLOW NO ACCESS是唯一支持的访问级别;
索引重组具有下列要求:
①对索引、表具有sysadm、sysmaint、sysctrl或者dbadm权限,或者具有control特权;
②用于存储索引的表空间的可用空间大于或等于索引的当前大小,在发出create table时,考虑在大型表空间中重组索引;
③其他日志空间,索引重组需要记录其活动;
11.3.2.2.确定何时重组表和索引
在对表数据进行许多更改之后,逻辑上连续的数据可能会位于不连续的物理数据页上,在许多更新操作创建了溢出overflow记录时更是如此,按这种方式组织数据时,数据库管理器必须执行额外的读操作才能访问顺序数据,另外删除大量数据后,其空间并没有释放,也需要额外的读操作;
表重组通过整理数据碎片来减少浪费的空间,并对行进行重排序来合并溢出记录,从而加快数据访问速度并最终提高查询性能。还可以指定根据特定索引来重新排序数据,以便查询通过最少的IO读取操作就可以访问数据;
对表数据进行大量更改将导致更新索引并使得索引性能下降。索引叶子页可能变成碎片或出现不良集群情况,并且索引有可能形成比所需层次level要多的层次以获得最佳性能。
所有这些问题都会产生更多IO并导致性能下降;下列任何情况都需要我们重组表或索引:
①自上次重组表之后,对查询访问的表进行了大量的插入、更新、删除操作;
②对于使用具有高聚合度的索引的查询,其性能发生了明显变化;
③在执行RUNSTATS来刷新统计信息后,性能没有得到改善;
④reorgchk指示需要reorg table或者reorg index;
⑤综合考虑查询性能不断降低所浪费的成本、重组表所需的成本,来确定是否进行表重组;
11.3.2.3.是否确定要重组表或索引
要确定是否需要重组表或索引,需要查询系统目录表中的统计信息,并监视下列统计信息:
①行的溢出:查询sysstat.tables视图中的overflow列来监视溢出值。因为当表中的可变长度列导致记录长度变长后,以至于它们不能放入数据页上的指定位置时,则表示行数据会溢出。
在列添加到表定义并稍后通过更新行来更新该列时,长度可能会更改。在这些情况下,在行中的原始位置将保留一个指针,而实际值则存储在由指针指示的另一个位置。这可能会影响性能,毕竟数据库管理器必须根据指针来查找行的内容,从而增加了处理时间、IO数目;
而reorg table则会消除行溢出,如果行溢出数量较多,则reorg table效果就越明显;
②访存统计信息:查询syscat.indexes和sysstat.indexes下面的3个列来确定预取程序的效率,这些统计信息对照基表来体现预取程序的平均性能特征:
average_sequence_fetch_pages:存储可以按表中顺序访问的平均页数;较小的数目指示预取程序没有充分发挥作用,原因是它们不能读入由表空间的prefetchsize设置指定的所有页数。较大的数目指示预取程序将有效的执行。对于集群索引和表,此数目应该接近npages的值;
average_random_fetch_pages:存储当使用索引来访存表行时在顺序页访问之间的平均随机表页数。
average_sequence_fetch_gap:存储当使用索引进行访存时表页序列之间的平均间隔。
③包含标记为已删除,但未除去的RID的索引叶子页数:查询syscat.indexes、sysstat.indexes统计信息表的num_enpty_leafs列。
④索引的聚合比率和聚合因子统计信息
⑤索引叶子页数
⑥空数据页的数目
11.3.3.重组表和索引的成本
REORG TABLE/REORG INDEX成本包括:
①执行REORG命令时消耗的CPU;
②由于REORG命令会导致并行性降低,这是因为REORG要求锁定而导致数据库并行性降低;
③需要额外的存储空间:
1>脱机表重组需要额外的存储空间来保存表的影子副本;
2>联机表重组需要更多的日志记录空间;
3>联机索引重组需要额外的存储空间来保存索引的影子副本;
4>联机索引重组需要更多的日志空间;
5>脱机索引重组将使用较少的日志空间,并且不涉及影子副本;
11.3.5.启用表和索引的自动重组
DB2 V8之后,可以使用自动表重组来启用DB2管理脱机和索引重组,但自动表重组是数据库控制的,人工不能干预,很可能在业务高峰期开始了自动表重组,这会影响性能,因此建议在充分了解业务逻辑的前提下,通过编写crontab脚本,在合适时间调度执行碎片整理。
11.4.碎片整理案例分析
db2 reorgchk update statistics on table db2admin.employee
在列表信息中的F4(clusterratio or normalized clusterfactor > 80)指示索引是否需要reorg;该索引与基本表不在相同的序列中。当在表中定义了多个索引时,一个或多个索引可能被标记为需要REORG,指定REORG顺序的最重要索引;
reorgchk结果说明 | ||
表说明 | F1 | 属于溢出记录的行所占的百分比。当这个百分比大于5%时,F1列中将有一个星号* |
F2 | 数据页中使用了的空间所占的百分比。当这个百分比小于70%时,F2列中将有一个星号* | |
F3 | 其中含有包含某些记录的数据的页所占的百分比。当这个百分比小于80%时,F3列中将有一个星号* | |
索引说明 | F4 | 群集率,即表中与索引具有相同顺序的行所占的百分比。当这个百分比小于80%时,F4列中将有一个星号* |
F5 | 在每个索引页上用于索引键的空间所占的百分比。当这个百分比小于50%时,F5列中将有一个星号* | |
F6 | 可以存储在每个索引级的键的数目。当这个百分比小于100时,F6列中将有一个星号* | |
F7 | 在一个页中被标记为deleted的记录ID所占的百分比。当这个百分比大于20%时,F7列中将有一个星号* | |
F8 | 索引中空叶子页所占的百分比。当这个百分比大于20%时,F8列中将有一个星号* |
①F1-F8中任何一个列有*,则说明当前的表/索引应该重组;
②根据reorgchk给出的提示信息,结合SQL语句自身,建立适当的索引;
③根据实际情况,reorg table或者reorg index;
④更新表,索引的统计信息;
11.6.重新绑定程序包
重新绑定是为先前已经绑定的应用程序重新创建程序包的过程。
每个在数据库中执行的应用程序在执行之前都需要有一个绑定过程,这个绑定过程会根据数据库中各种统计信息、数据库对象的情况来创建一个程序包,这个程序包中通常就是执行计划,因此,当统计信息修改后,或者,数据库对象修改后,就需要对数据库中受影响的应用程序执行重新绑定,这样才能允许应用程序应用到最新的更新。
syscat.packages的valid列标识当前的程序包是否可用,如果值为X则表示当前的程序包是不可用的,此程序包需要重新绑定。
统计信息更新runstats、碎片整理reorg、统计信息更新后都需要重新绑定。
重新绑定有2个命令:rebind、db2rbind;
rebind重新创建数据库中已经存在的程序包,而db2rbind重新绑定数据库中存在的所有程序包。
11.7.DB2健康检查
11.7.1.查看是否有僵尸实例进程
通过db2_ps或者ps -ef|grep -i instname来查看实例的所有进程,举个例子:
ps -emo THREAD | grep -i Z | grep -i db2inst1
11.7.2.检查数据库是否一致
一致性指的是:提交的事务都已经写到磁盘上了,且任何未提交的事务都不在磁盘上,那么数据库就是一致的。
实际情况是,当某些程序连接到数据库并进行修改后提交事务,但修改的内容并没有写入到磁盘上,这里就有一致性的问题了,可以用inspect命令来检查,例如:
db2 inspect check database results keep db_check.out
DB20000I INSPECT命令成功完成
db2inspf db_check.out db_check.txt
最后检查db_check.txt查看数据库是否一致
11.7.3.查找诊断日志来判断是否有异常
错误和消息日志会记录到db2diag.log和instance_ID.nfy中,其中的通知日志instance_ID.nfy包含用于DBA的消息,而db2diag.log记录关于DB2的问题。
DB2提供了db2diag工具来对db2diag.log中的信息进行过滤、格式化。
11.7.4.检查数据库备份完整性、日志归档是否正常
db2 list distory backup all for dbName
名词说明:db2的日志放在logpath中,由于logpath大小固定,当满了之后统一归档放到logarchmeth1中,如果不归档的话,则后面新内容覆盖掉之前的旧内容。
11.7.6.查看磁盘空间
通过db2 get db cfg来查看活动日志目录,找到目录后再通过操作系统命令,例如df -g来查看该目录剩余多少使用空间。
对于DMS表空间来说,需要使用db2 list tablespaces show detail来查看,因为DMS表空间是预先分配的。
11.8.数据库监控
11.8.1.监控工具
监控的一个宗旨就是:DB2、服务器操作系统同时监控,而不能单独监控其中的某一个;
针对操作系统,可以是vmstat/sar/nmon/top/glance等;
针对DB2,则有很多,例如:
监控数据库和实例 | Snapshot monitors/event monitor/sysibmadm动态性能视图 |
日志 | 通知日志/db2diag.log的db2diag命令/memory visualizer |
11.8.2.计算数据库的大小
通过执行存储过程get_dbsize_info来计算出数据库的大小、最大容量。
11.8.3.监控表的物理大小
select fpages from syscat.tables where tabname=’T1’;
11.8.4.监控数据库实用工具的进度
db2 list utilities show detail
11.8.5.监控数据库crash recovery进度
db2pd -db dbname -recovery
11.8.6.监控正在reorg的表
select * from sysibmadm.snaptab_reorg
11.8.7.监控高成本应用程序
select agent_id,percent_rows_selected from sysibmadm.appl_performance;
11.8.8.监控正在执行的时间最长的SQL语句
Select num_executions,average_execution_time_s,prep_time_percent from sysibmadm.query_prep_cost order by num_executions desc
11.8.9.监控执行次数最多的SQL语句
Select * from sysibmadm.top_dynamic_sql order by num_executions desc fetch first 5 rows only
11.8.10.监控执行时间最长的SQL语句
Select * from sysibmadm.top_dynamic_sql order by average_executions desc fetch first 5 rows only
11.8.11.监控排序次数最多的SQL语句
11.8.12.监控引起锁等待的SQL语句
11.8.13.检查表空间状态
db2 list tablespaces show detail
11.8.14.检查表状态
Select status from syscat.tables where tabname=’XXX’
11.8.15.查找需要RUNSTATS的表和索引
①select tabname,INDNAME from syscat.indexes where stats_time is null;
②select tabname from syscat.tables where stats_time is null;
为了捕捉表及其索引的统计信息,使用如下命令:
runstats on table schema.tabname with distribution and detailed indexes all;
11.8.16.定期清理db2diag.log文件