跳转到主要内容

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

当您初次登录到 developerWorks 时,将会为您创建一份概要信息。您在 developerWorks 概要信息中选择公开的信息将公开显示给其他人,但您可以随时修改这些信息的显示状态。您的姓名(除非选择隐藏)和昵称将和您在 developerWorks 发布的内容一同显示。

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

  • 关闭 [x]

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

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

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

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

  • 关闭 [x]

实例详解 DB2 排序监控和调优

徐明伟, DB2 独立咨询顾问, 北京普远天成科技有限公司
徐明伟,高级 DBA 认证管理员,曾经在 IBM 软件服务部工作 5 年,专注于 DB2 咨询和服务。擅长 DB2 数据库规划、运维管理、性能调优和问题诊断。北京普远天成科技有限公司技术总监。
蔡铭洁, 软件工程师, IBM
蔡铭洁,就职于 IBM 中国系统与科技中心 STG Rational Solution Team 近 3 年,从事 Rational 相关产品、解决方案的开发和支持,熟悉 IBM i/AIX 平台上 DB2 产品以及 SQL 语句调优。
孙云峰, 高级产品经理, 深圳市共济科技有限公司
孙云峰,高级 DBA 认证管理员,曾就职于 IBM 中国软件开发中心近 7 年,从事 IBM InfoSphere Federation Server 的开发和全球售后服务支持。是 IBM 授权的官方高级培训讲师。深圳市共济科技有限公司高级产品经理。

简介: 在 DB2 数据库系统中,排序对 CPU 的影响很大。在笔者的培训和性能调优经历中,经常发现很多用户对排序的原理缺乏了解,当遇到性能瓶颈时,无法进行有效的监控和优化。本文首先介绍了 DB2 的排序理论和参数,然后通过实例详细说明排序问题的监控诊断方法,最后探讨了排序调优的建议。

发布日期: 2011 年 12 月 22 日
级别: 中级
访问情况 : 779 次浏览
评论: 


免费下载:IBM® DB2® Express-C 9.7.2 免费版 或者 DB2® 9.7 for Linux®, UNIX®, and Windows® 试用版
下载更多的 IBM 软件试用版,并加入 IBM 软件下载与技术交流群组,参与在线交流。

概述

在 DB2 数据库系统监控中,经常会遇到 CPU 资源使用过高问题,造成此类问题的原因很多,但最主要的原因有两个,第一是过多的逻辑 I/O 读取,第二就是过多的排序 (Sort),这两个因素有时也称为 CPU 的两大杀手。所谓过多的逻辑 I/O 读取,通常指发生在缓冲池中的表扫描。

排序是指对某些数据按照某个 ( 或某些 ) 字段从大到小或从小到大排列的过程。比如,按照学生成绩从高到低排序,根据姓氏字母顺序排序等。

在 DB2 数据库中,哪些操作会引起表数据排序呢?熟悉 SQL 的朋友立即会想到 Order By。没错,如果排序字段上没有索引,或者 DB2 认为索引的开销比表扫描更大时,DB2 就会对数据进行排序。

除 Order By 之外,在以下操作中也可能引起排序:

  1. 对于包含 DISTINCT,,GROUP BY, HAVING,INTERSECT,EXCEPT,UNION 等操作的 SQL 语句,如果没有索引满足所取的行的顺序要求,或者优化器认为排序的代价低于索引扫描,就需要进行排序;
  2. 对于包含 Max/Min/Sum/Cube/Rollup/Rank 等聚集函数,DB2 会把语句重写为一个使用排序的嵌套子查询;
  3. 对于 Reorg, Create Index 等操作,需要对表数据进行排序才能完成;
  4. 对于查询计划中的 Dynamic Bitmap Index ANDing(IXAND),Hash Join(HSJOIN)等操作的生成的 Hash 表会放在 SORTHEAP 中。

通常情况下,大量的排序会对性能造成极大影响。比如,排序会导致很高的 CPU 使用时间;增加 SQL 执行时间;增加锁超时和死锁发生的机率;排序会严重消耗有限的内存空间;排序溢出会引起临时表空间的频繁 I/O 等。在实际运维过程中,经常发现很多人对排序的监控和调优缺乏理论和实践经验,遇到相关问题时不知所措。本节首先介绍排序的原理,然后通过一个实例介绍排序的监控和诊断方法,最后提出减少排序的建议,希望对大家有所帮助。

排序的原理

正常情况下,DB2 排序发生在内存中,这块内存叫做排序堆,即 SORTHEAP。当需要排序的数据超出 SORTHEAP 大小限制时,就会发生排序溢出。溢出的数据会写到临时表中,这会产生更多的 I/O,因此对性能会有较大影响。

通过图 2-1 可知,DB2 的内存集包括实例内存集、数据库共享内存集、应用程序内存集和代理私有内存集等。内存池是从内存集中分配的。根据排序内存池的分配来源,分为私有排序和共享排序。私有排序是从代理私有内存集中分配的,而共享排序从数据库共享内存集中分配。


图 1.排序内存
图 1.排序内存

SORTHEAP: 数据库配置参数,指定为每个排序分配的最大内存大小,实际使用的大小是由优化器来决定的。如果表的统计信息不准确,会导致优化器对要使用的排序内存的大小估算不准,有可能分配比实际需要少的内存,导致不必要的排序溢出。这就提醒我们要经常使用 runstat 来更新有频繁数据更改的表的统计信息。

SHEAPTHRES_SHR: 数据库配置参数,该参数指定了数据库共享内存集中共享排序内存池的大小,它限制了该数据库上的所有应用能达到的共享排序内存上限。在 DB2 8 版本中,这个值是硬限制,当达到此限制后,请求排序的新应用会收到 SQL0955(reason code 2) 错误。从 DB2 9.1 起,这个参数改为软限制,超过 SHEAPTHRES_SHR 的共享排序请求可以从数据共享内存集的溢出区 (Database overflow Buffer) 获得。

SHEAPTHRES: 实例配置参数 , 指定为本实例中所有私有排序分配的内存上限的软限制。当私有排序分配的内存达到了此限制,新请求的私有排序的内存大小分配将会小于 sortheap 配置的大小。

简单地说,每次排序是从 SORTHEAP 中分配的。如果使用私有排序,那么允许分配的排序内存大小不能超过 SHEAPTHRES 实例参数;如果使用共享排序,允许分配的排序内存大小不能超过 SHEAPTHRES_SHR 数据库参数。

那么如何配置 DB2 使用共享排序还是私有排序呢?从 DB2 9 开始,如果将 SHEAPTHRES 实例参数设置为 0,DB2 将使用共享排序,即排序内存从共享排序内存池中分配,排序内存的最大限制由 SHEAPTHRES_SHR 决定。

排序的监控

DB2 排序可以通过 SNAPSHOT 快照监控,快照监控结果提供了很多关于排序的信息,如总的排序次数、排序时间、排序溢出数量等。以下是数据库快照排序监控指标:


清单 1. 数据库快照排序监控指标
				
 inst20@db2server:/data1/sh> db2 get snapshot for database on perfdb | more 

              Database Snapshot 
 Total Private Sort heap allocated          = 9553 
 Total Shared Sort heap allocated           = 0 
 Shared Sort heap high water mark           = 0 
 Total sorts                                = 12936047 
 Total sort time (ms)                       = 19098348 
 Sort overflows                             = 83950 
 Active sorts                               = 1 

… …
 Commit statements attempted                = 1130957 
 Rollback statements attempted              = 519 


Total sorts:表示发生的总排序次数; Total sort time(ms):表示发生的总排序时间; Sort overflows:表示发生的排序溢出次数; Active sorts:表示监控时正在进行的排序次数。

前三个指标是自数据库启动以来的统计值,最后一个指标是当前值。几个关键的指标如下:

  1. Sort overflows/Total sorts * 100% 表示排序溢出百分比,通常情况下,该值应该小于 3。如果大于 3,表示溢出的比例太高,需要优化;
  2. Total sorts time(ms)/Total sorts 表示每次排序花费的时间 ( 毫秒 ),对于交易系统来说,该值最好小于 50ms;
  3. Total sorts time(ms)/(Commit statements attempted + Rollback statements attempted) 表示每个事务花费在排序上的时间。一个事务响应时间包含很多方面,比如读 / 写时间、锁时间、排序时间、CPU 时间等。排序时间越少,最终用户的响应时间也越快,占用的 CPU 资源也越少。

上例中,在 4 天的时间内共计发生了 12936047 次排序,排序溢出比为 83950/12936047=0.6%,每个事务需要花费的排序时间为:19098348/(1130957+519) = 16ms。

除了数据库快照,应用程序快照、动态 SQL 快照也包含一些排序信息。这对于我们定位排序根源有很大帮助。以下是动态 SQL 语句快照片段,该语句平均每次执行需要 4 次排序,而且 3 次发生溢出,根据这些信息,该语句很明显需要优化。


清单 2. 动态 SQL 语句快照片段
					
 Number of executions               = 36 
 Number of compilations             = 1 
 Worst preparation time (ms)        = 18 
 Best preparation time (ms)         = 15 
 Internal rows deleted              = 0 
 Internal rows inserted             = 0 
 Rows read                          = 57462636 
 Internal rows updated              = 0 
 Rows written                       = 30062371 
 Statement sorts                 = 144
					Statement sort overflows        = 108
					Total sort time                 = 145700
 Buffer pool data logical reads     = 19546362 
 Buffer pool data physical reads    = 8 
 Buffer pool temporary data logical reads   = 4141609 
 Buffer pool temporary data physical reads  = 250 
 Buffer pool index logical reads    = 35513607 
 Buffer pool index physical reads   = 1096 
 Buffer pool temporary index logical reads  = 0 
 Buffer pool temporary index physical reads = 0 
 Total execution time (sec.ms)      = 355.390643 
 Total user cpu time (sec.ms)       = 164.663270 
 Total system cpu time (sec.ms)     = 1.529099 
 Statement text                     = select * from … ( 略 ) 

排序的优化

以上我们介绍了排序的监控,当发现排序的监控指标超出期望值时,就需要优化。影响排序的因素主要包括排序的行数、排序列的宽度和 ORDER BY 的列数等,排序的行数乘以排序列的宽度决定了一次排序占用的空间,因此,应该尽量减少排序的行数 ( 很多情况下,排序列无法更改 )。以下介绍一些常用的排序优化方法。

1.参数调优

从 DB29 开始,SHEAPTHRES_SHR 实例参数的缺省值为 0,这表示排序内存从数据库共享内存区分配,排序总量由 SHEAPTHRES 数据库参数控制。 那么,如何设置 SORTHEAP 和 SHEAPTHRES 的大小呢?

首先 SORTHEAP 是每次排序能够分配的最大内存空间,当排序的数值超过该值时,就要发生排序溢出,SORTHEAP 的缺省大小是 256 页,即 1M。假定,要排序的数据每行是 1K 大小,那么每个 SORTHEAP 最多允许排序 1M/1K=1000 行,超出 1000 行数据,排序将会溢出。

 inst20@db2server:/data1/sh> db2 get db cfg for sample | grep -i sort 
 Sort heap thres for shared sorts (4KB) (SHEAPTHRES_SHR) = 5000 
 Sort list heap (4KB)                         (SORTHEAP) = 256 

对于数据仓库系统来说,一般行记录很长,排序的行数也很多,这是可考虑适当增大 SORTHEAP 大小,但不要扩的太大。

SHEAPTHRES_SHR 参数,用来限定所有排序可以占用的内存空间。该值的大小由两个指标来决定,一个是 SORTHEAP,另外一个是同时排序的个数。但是,同时排序的个数很难估计,一般采用并发数来估计。以下的监控结果可知,当时正在并发的应用数量大概是 10 个。

 db2inst1@ibmswg01:~/> db2 get snapshot for database on prefdb 
 Appls. executing in db manager currently   = 10 

考虑到单个应用可能需要进行多次排序,可设置: SHEAPTHRES_SHR = SORTHEAP * 应用并发数 * 2 在 9.1 及以上版本,DB2 提供了自动调优功能 (STMM),好处是 DB2 根据工作负载和资源情况,决定一些内存的分配和回收,比如:缓冲池、排序堆、锁列表和 Package cache 大小,当需要排序时,可以从别的内存区借用,当不需要时归回,充分利用内存使用。对于运行稳定的系统,可考虑启用 STMM,设置这两个参数为 automatic 自动值。

 inst20@db2server:/data1/sh> db2 update db cfg for perfdb using SORTHEAP automatic 
 inst20@db2server:/data1/sh> db2 update db cfg for perfdb using SHEAPTHRES_SHR automatic 

2. 物理设计优化

调整参数有些情况下能解决问题,但可能会隐藏问题,因为调参只是尽量减少排序溢出的几率,并不能减少排序的次数。因此,作为一个优秀的 DBA,需要挖掘排序的根源,并给出解决方案。根源是什么?尽管 Reorg、建索引等操作需要排序,但几乎 99% 的概率是 SQL 语句引起的。在 SQL 语句无法更改的情况下,作为 DBA,能够做的就是在物理设计上做优化。 那么如何找到哪些语句发生了大量排序呢?答案就是我们前面介绍过的动态 SQL 快照和应用快照监控。 当找到 SQL 语句后,就可以通过一些物理设计来优化 SQL,如索引、物化视图 (MQT) 等。当然,一些影响优化器的运维工作也必不可少,如 runstats,reorg,rebind 等操作。 索引是减少排序的利器,因为索引本身已经是经过排序的数状结构。创建合适的索引会大大减少、甚至避免排序。当 SQL 语句中出现以下操作时,可以考虑在相应的字段上创建索引:

  1. Order By/Group By 操作,如: SELECT a,b,c FROM tab1 ORDER BY a,b SELECT a,b,c FROM tab1 WHERE a=100 ORDER BY b SELECT a,b,count(*),sum(*) FROM tab1 group by a,b 这时可考虑在 tab1(a,b) 上建索引。
  2. Distinct 操作,如:SELECT distinct a FROM tab1 可考虑在 tab(a) 上建索引,对于 distinct 的查询可避免排序。
  3. Hash Join 操作需要在 SORTHEAP 中建立哈希表,对于发生大量 Hash Join 的表,可考虑建立索引。
  4. Create index idx_1 on tab1(a) allow reverse scan 建索引时考虑用 Allow Reverse Scans 进行索引值逆向扫描,这也是 DB2 9 的缺省选项。

3. 调优 SQL 语句

如果通过 3.1 和 3.2 的步骤仍然不能解决排序问题,那就需要对 SQL 语句本身进行逻辑调整和修改。比如:

  1. 能否在 SQL 语句中省略 ORDER BY, DISTINCT 等操作,如果无法省略,能否尽量减少排序的行数或列数,比如通过增加过滤条件等;
  2. 如果 UNION All 能满足需求,就避免用 UNION,因为 UNION All 不需要排序;
  3. 写优化的 SQL 语句,比如不要在排序字段上使用函数。

排序问题的诊断分析

下面我们通过一个详细的例子说明对排序问题的诊断分析过程。

搭建实验环境

以下实验在 DB2 Version 9.5 for Linux 下运行。首先创建一个 SORTDB 数据库,然后创建一个 EMPLOYEE 员工表,并插入 100 万行数据,其中 DEPT_ID 字段是随机产生的 1000 个部门编号,所有员工数据均匀分布在 1000 个部门里,每个部门大概包含 100 万 /1000=1000 个员工。 脚本如下 ( 以下命令存到一个脚本文件中 create.ddl):

 -- 创建测试 database 
 create db sortdb@ 

 -- 更改日志参数,否则会在插入数据时出现 log full 
 update db cfg for sortdb using logfilsiz 2000 @ 
 update db cfg for sortdb using logprimary 20@ 
 update db cfg for sortdb using logsecond 30@ 

 -- 日志参数的更改需要断掉连接才会生效                                               
 force applications all@ 

 -- 连接数据库                                               
 connect to sortdb@ 

 -- 创建 bufferpool 
 create bufferpool bp4k size 10000@ 

 -- 创建 automatic storaged tablespace 
 create tablespace emp_dms bufferpool bp4k@ 

 -- 创建 table 
 create table db2inst1.employee 
 (  emp_id int not null primary key, 
   name char(20), 
   dept_id int, 
   salary decimal, 
   address char(30), 
   remark char(40) 
 ) in emp_dms 
 @ 
                                                                                         
 -- 向表里插入 100 万条数据,其中 dept_id 的范围为 0-1000,其余几个 char 字段值都是根据 count 值产生
 begin atomic                                                                             
   declare count int default 1;                                                          
   while (count <1000000) do                                                             
     insert into db2inst1.employee values(                                               
        count,                                                                           
        '--emp' concat char(count),                                                      
        ceiling( (rand()*1000) ),                                                        
        20000.50,                                                                        
        '-----address' concat char(count) concat '---',                                  
        '------remark' concat char(count) concat '----'                                  
     );                                                                                  
                                                                                         
     set count=count+1;                                                                  
   end while;                                                                            
 end                                                                                      
 @                                                                                        

 -- 对表做 runstats 
 runstats on table db2inst1.employee @ 

执行 db2 -td@ -f create.ddl 命令创建脚本。

然后设置排序参数,sortheap=250,sheapthresshr=1000,并打开监控开关。

 inst20@db2server:/backup> db2 update db cfg for sortdb using sheapthres_shr 10000 
 sortheap 250 
 DB20000I  The UPDATE DATABASE CONFIGURATION command completed successfully. 

 inst20@db2server:/backup> db2 update dbm cfg using SHEAPTHRES 0 
 DB20000I  The UPDATE DATABASE MANAGER CONFIGURATION command completed successfully. 

 inst20@db2server:/backup> db2 UPDATE DBM CFG USING DFT_MON_SORT ON 
 DB20000I  The UPDATE DATABASE MANAGER CONFIGURATION command completed successfully. 

 inst20@db2server:/backup> db2stop force 
 06/03/2011 07:33:04     0   0   SQL1064N  DB2STOP processing was successful. 
 inst20@db2server:/backup> db2start 
 06/03/2011 07:33:15     0   0   SQL1063N  DB2START processing was successful.  

然后查询 dept_id < 100 的记录,并按 dept_id 排序,大概会有 9 万 9 千行记录返回。

 inst20@db2server:/backup> db2 "SELECT dept_id, name FROM db2inst1.employee WHERE 
 dept_id <100 ORDER BY dept_id" | grep selected 
 99011 record(s) selected. 

对排序问题的诊断和分析

现在我们要通过数据库监控,查找排序问题的根源。

1.数据库监控分析
通过监控结果可知,在共享内存区发生了一次排序,并且发生了排序溢出,排序时间是 204ms。以下监控是 SQL 语句完成后执行的,所以 Total Shared Sort heap allocated 的结果是 0,否则会显示当前分配的排序堆页数。因为是共享排序,所有与私有排序相关的参数都是 0。

 inst20@db2server:/backup> db2 get snapshot for db on sortdb | more 
 Total Private Sort heap allocated          = 0 
 Total Shared Sort heap allocated           = 0 
 Shared Sort heap high water mark           = 250 
 Post threshold sorts (shared memory)       = 0 
 Total sorts                                = 1 
 Total sort time (ms)                       = 206 
 Sort overflows                             = 1 
 Active sorts                               = 0 

然后监控缓冲池临时数据和临时索引的逻辑读 / 写页数,当排序溢出时,会溢出到临时表空间中。如果发现临时数据读写值较高,那么很可能是 SORT 引起的。

 inst20@db2server:/backup> db2 get snapshot for database 
on sortdb|grep -i "temporary data"

 Buffer pool temporary data logical reads   = 1792 
 Buffer pool temporary data physical reads  = 31 
 Buffer pool temporary index logical reads  = 0 
 Buffer pool temporary index physical reads = 0 

2.监控 SQL 语句
接着根据动态 SQL 语句快照,找到排序多、溢出多的 SQL 语句。我们会发现,该语句执行了一次,执行时间花费了 7.6 秒,Rows Read=1099018, Rows Written= 99011。排序发生了一次,溢出一次。可能有人有会比较奇怪,为什么 select 语句会产生 rows written 呢?这就是因为排序溢出写到临时表空间,产生了写 I/O,溢出的行数为 99011,正对应前面的查询结果。

 
 Number of executions               = 1 
 Number of compilations             = 1 
 Worst preparation time (ms)        = 134 
 Best preparation time (ms)         = 134 
 Internal rows deleted              = 0 
 Internal rows inserted             = 0 
 Rows read                          = 1099018 
 Internal rows updated              = 0 
 Rows written                       = 99011 
 Statement sorts                    = 1 
 Statement sort overflows           = 1 
 Total sort time                    = 204 
 Buffer pool data logical reads     = 30561 
 Buffer pool data physical reads    = 2367 
 Buffer pool temporary data logical reads   = 1792 
 Buffer pool temporary data physical reads  = 1 
 Buffer pool index logical reads    = 35 
 Buffer pool index physical reads   = 27 
 Buffer pool temporary index logical reads  = 0 
 Buffer pool temporary index physical reads = 0 
 Buffer pool xda logical reads      = 0 
 Buffer pool xda physical reads     = 0 
 Buffer pool temporary xda logical reads    = 0 
 Buffer pool temporary xda physical reads   = 0 
 Total execution time (sec.microsec)= 7.612814 
 Total user cpu time (sec.microsec) = 0.938412 
 Total system cpu time (sec.microsec)= 0.000000 
 Total statistic fabrication time (milliseconds) = 0 
 Total synchronous runstats time  (milliseconds) = 0 
 Statement text                     = SELECT dept_id, name FROM db2inst1.employee 
 WHERE dept_id < 100 ORDER BY dept_id 

当然,也可以使用 SYSIBMADM.SNAPDYN_SQL 管理视图找到排序最多的动态 SQL 语句。

3.SQL 语句分析
通过 explain 工具生成 SQL 语句的执行计划,并通过 db2exfmt 进行格式化。

 
 inst20@db2server:~/sqllib/misc> db2 -tvf EXPLAIN.DDL 
 inst20@db2server:~> more query.sql 
 SELECT dept_id, name FROM db2inst1.employee WHERE dept_id < 100 ORDER BY dept_id; 

 inst20@db2server:~> db2 set current explain mode explain 
 DB20000I  The SQL command completed successfully. 

 inst20@db2server:~> db2 -tvf query.sql 
 SELECT dept_id, name FROM db2inst1.employee WHERE dept_id < 100 ORDER BY dept_id 
 SQL0217W  The statement was not executed as only Explain information requests are 
 being processed.  SQLSTATE=01604 

 inst20@db2server:~> db2exfmt -1 -d sortdb -o query_exfmt.out 

然后打开 query_exfmt.out 文件,计划如下:

 
 Access Plan: 
 ----------- 
        Total Cost:             36010 
        Query Degree:           1 

      Rows 
     RETURN 
     (   1) 
      Cost 
       I/O 
       | 
     98999.9 
     TBSCAN 
     (   2) 
      36010 
   30763
       | 
     98999.9 
     SORT 
     (   3) 
     35270.1 
  30094.5
       | 
     98999.9 
     TBSCAN 
     (   4) 
     30134.7 
  29426
       | 
     999999 
 TABLE: DB2INST1 
    EMPLOYEE 
       Q1 

通过以上结果可知,在对表 EMPLOYEE 进行 TBSCAN 后,有一次 SORT 操作,然后对 SORT 的结果再次 TBSCAN。观察 TBSCAN(4),SORT(3) 和 TBSCAN(2)这三个操作符的累计 I/O 次数,可以看出 I/O 在增长,这是个典型的 SORT 溢出。 那么再看 SORT 操作符的具体信息:

3) SORT  : (Sort) 
	Cumulative Total Cost:          35270.1 
	Cumulative CPU Cost:            2.59546e+09 
	Cumulative I/O Cost:            30094.5 
	Cumulative Re-Total Cost:       0 
	Cumulative Re-CPU Cost:         0 
	Cumulative Re-I/O Cost:         668.5 
	Cumulative First Row Cost:      35270.1 
	Estimated Bufferpool Buffers:   30318 
	
	Arguments: 
	--------- 
	DUPLWARN: (Duplicates Warning flag) 
			FALSE 
	NUMROWS : (Estimated number of rows) 
			99000 
	ROWWIDTH: (Estimated width of rows) 
			32 
	SORTKEY : (Sort Key column) 
			1: Q1.DEPT_ID(A) 
	SPILLED : (Pages spilled to bufferpool or disk) 
			892 
	TEMPSIZE: (Temporary Table Page Size) 
			4096 
	UNIQUE  : (Uniqueness required flag) 
			FALSE 

Input Streams: 
------------- 
2) From Operator #4 

		Estimated number of rows:       98999.9 
		Number of columns:              2 
		Subquery predicate ID:          Not Applicable 

		Column Names: 
		------------ 
		+Q1.NAME+Q1.DEPT_ID 

Output Streams: 
-------------- 
3) To Operator #2 

		Estimated number of rows:       98999.9 
		Number of columns:              2 
		Subquery predicate ID:          Not Applicable 

		Column Names: 
		------------ 
		+Q1.DEPT_ID(A)+Q1.NAME 

通过以上排序操作可知,有 892 页发生了排序溢出。DB2 优化器预测的排序行数是 99000 行,每行宽度是 32 个字节,所以需要的排序空间至少是 99000*32/1024=3093k=3.1M 左右,而 SORTHEAP 设定的排序内存是 250*4K=1M,所以发生了排序溢出。

排序溢出处理

发生排序溢出时,第一个要考虑的就是调整 SORTHEAP 参数,本例中我们将 SORTHEAP 参数值由 250 页 (1M) 增加到 2500 页 (10M)。为便于对比,我们把以前的监控结果清零。

 inst20@db2server:~> db2 update db cfg for sortdb using sortheap 2500 
 DB20000I  The UPDATE DATABASE CONFIGURATION command completed successfully. 
 inst20@db2server:~> 
 inst20@db2server:~> 
 inst20@db2server:~> db2 reset monitor all 
 DB20000I  The RESET MONITOR command completed successfully. 

然后再次执行 SQL 语句,并观察结果。没有发现排序溢出,并且排序时间是 162ms,小于之前的 206ms。

 [db2inst1@ibmswg01]$ db2 get snapshot for db on sortdb | more 
 Total Private Sort heap allocated          = 0 
 Total Shared Sort heap allocated           = 0 
 Shared Sort heap high water mark           = 2322 
 Post threshold sorts (shared memory)       = 0 
 Total sorts                                = 1 
 Total sort time (ms)                       = 162 
 Sort overflows                             = 0 
 Active sorts                               = 0 

再次查看 SQL 语句的执行计划,

 Access Plan: 
 ----------- 
        Total Cost:             30201.9 
        Query Degree:           1 

      Rows 
     RETURN 
     (   1) 
      Cost 
       I/O 
       | 
     98999.9 
     TBSCAN 
     (   2) 
     30201.9 
      29426 
       | 
     98999.9 
     SORT 
     (   3) 
     30201.9 
      29426 
       | 
     98999.9 
     TBSCAN 
     (   4) 
     30134.7 
      29426 
       | 
     999999 
 TABLE: DB2INST1 
    EMPLOYEE 
       Q1 

 3) SORT  : (Sort) 
	Cumulative Total Cost:          30201.9 
	Cumulative CPU Cost:            2.55223e+09 
	Cumulative I/O Cost:            29426 
	Cumulative Re-Total Cost:       30134.6 
	Cumulative Re-CPU Cost:         2.34872e+09 
	Cumulative Re-I/O Cost:         0 
	Cumulative First Row Cost:      30201.9 
	Estimated Bufferpool Buffers:   29426 

	Arguments: 
	--------- 
	DUPLWARN: (Duplicates Warning flag) 
			FALSE 
	NUMROWS : (Estimated number of rows) 
			99000 
	ROWWIDTH: (Estimated width of rows) 
			32 
	SORTKEY : (Sort Key column) 
			1: Q1.DEPT_ID(A) 
	TEMPSIZE: (Temporary Table Page Size) 
			4096 
	UNIQUE  : (Uniqueness required flag) 
			FALSE 

Input Streams: 
------------- 
2) From Operator #4 

		Estimated number of rows:       98999.9 
		Number of columns:              2 
		Subquery predicate ID:          Not Applicable 

		Column Names: 
		------------ 
		+Q1.NAME+Q1.DEPT_ID 

Output Streams: 
-------------- 
3) To Operator #2 

		Estimated number of rows:       98999.9 
		Number of columns:              2 
		Subquery predicate ID:          Not Applicable 

		Column Names: 
		------------ 
		+Q1.DEPT_ID(A)+Q1.NAME 

对比前面的访问计划,可以看到 TBSCAN(4),SORT(3) 和 TBSCAN(2)这三个操作符的累计 I/O 次数一直保持不变,SORT(3)操作中没有溢出。整个语句的 Cost 由 36010 降为 30201.9。

查看 SQL 语句执行时间,由 7.6 秒将为 6.97 秒。

消除排序

尽管调整参数后,排序溢出消失,但速度仍然较慢。接下来要做的是如何消除排序,采用的方法是创建索引。 DB2 提供了一个很有效的索引推荐工具,db2advis。

 db2advis -d sortdb -i advisesql.txt -n db2inst1 -o newindex.ddl 


从 newindex.ddl 可以看到,推荐了如下索引:
 -- LIST OF RECOMMENDED INDEXES 
 -- =========================== 
 -- index[1],   41.149MB 
   CREATE INDEX "DB2INST1"."IDX_EMP_DEPTID" ON "DB2INST1"."EMPLOYEE"
   ("DEPT_ID" ASC, "NAME" DESC) ALLOW REVERSE SCANS ; 
   COMMIT WORK ; 
   RUNSTATS ON TABLE "DB2INST1"."EMPLOYEE" FOR INDEX "DB2INST1"." IDX_EMP_DEPTID " ; 
   COMMIT WORK ; 

创建索引:

 db2 – tvf newindex.ddl 

再次执行 SQL 语句,观察生成的执行计划,这是一个非常的高效的索引只读计划,没有任何排序。整个语句的 Cost 也大幅降为 1147.64,SQL 语句的执行时间变为 3.9 秒。

 Access Plan: 
 ----------- 
        Total Cost:             1164.35 
        Query Degree:           1 

        Rows 
       RETURN 
       (   1) 
        Cost 
         I/O 
         | 
       98999.9 
       IXSCAN 
       (   2) 
       1164.35 
       1043.44 
         | 
       999999 
   INDEX: DB2INST1 
 IDX_EMP_DEPTID 
         Q1 

总结

本文讲解了 DB2 排序的概念,排序相关的配置和监控方法,并通过一个实例详细演示了排序问题的监控和调优,希望对大家有所帮助。


参考资料

学习

获得产品和技术

讨论

作者简介

徐明伟,高级 DBA 认证管理员,曾经在 IBM 软件服务部工作 5 年,专注于 DB2 咨询和服务。擅长 DB2 数据库规划、运维管理、性能调优和问题诊断。北京普远天成科技有限公司技术总监。

蔡铭洁,就职于 IBM 中国系统与科技中心 STG Rational Solution Team 近 3 年,从事 Rational 相关产品、解决方案的开发和支持,熟悉 IBM i/AIX 平台上 DB2 产品以及 SQL 语句调优。

孙云峰,高级 DBA 认证管理员,曾就职于 IBM 中国软件开发中心近 7 年,从事 IBM InfoSphere Federation Server 的开发和全球售后服务支持。是 IBM 授权的官方高级培训讲师。深圳市共济科技有限公司高级产品经理。

关于报告滥用的帮助

报告滥用

谢谢! 此内容已经标识给管理员注意。


关于报告滥用的帮助

报告滥用

报告滥用提交失败。 请稍后重试。


developerWorks:登录


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


忘记密码?
更改您的密码

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

 


当您初次登录到 developerWorks 时,将会为您创建一份概要信息。您在 developerWorks 概要信息中选择公开的信息将公开显示给其他人,但您可以随时修改这些信息的显示状态。您的姓名(除非选择隐藏)和昵称将和您在 developerWorks 发布的内容一同显示。

请选择您的昵称:

当您初次登录到 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=782381
ArticleTitle=实例详解 DB2 排序监控和调优
publish-date=12222011

标签

Help
使用 搜索 文本框在 My developerWorks 中查找包含该标签的所有内容。

使用 滑动条 调节标签的数量。

热门标签 显示了特定专区最受欢迎的标签(例如 Java technology,Linux,WebSphere)。

我的标签 显示了特定专区您标记的标签(例如 Java technology,Linux,WebSphere)。

使用搜索文本框在 My developerWorks 中查找包含该标签的所有内容。热门标签 显示了特定专区最受欢迎的标签(例如 Java technology,Linux,WebSphere)。我的标签 显示了特定专区您标记的标签(例如 Java technology,Linux,WebSphere)。