互联网服务数据库

DB2 性能优化快速入门

本文是针对 DB2® Universal Database(DB2 UDB)的初学者在遇到 DB2 的性能问题的时候不知道从何分析,从何入手的这一问题,从 DB2 的体系结构介绍开始,由浅入深的讲述了 DB2 性能优化的一些基础知识,简单地介绍调优的原理和工具。同时针对性能上的一些典型问题,如 DML 性能问题 (...显示全部
本文是针对 DB2® Universal Database(DB2 UDB)的初学者在遇到 DB2 的性能问题的时候不知道从何分析,从何入手的这一问题,从 DB2 的体系结构介绍开始,由浅入深的讲述了 DB2 性能优化的一些基础知识,简单地介绍调优的原理和工具。同时针对性能上的一些典型问题,如 DML 性能问题 ( 查询和插入操作 ), DDL 性能问题(建表,建索引),并发性问题等等,介绍一种渐进的分析方法,同时结合一些具体的优化案例进行分析以及成型的 DB2 调优工具 (DB2 Performance Expert) 的介绍,使得初学者能够在很短的时间内掌握 DB2 性能优化的基本技巧,并且能够在数据库早期设计时考虑到一些性能因素而防范于未然。 DB2 性能优化概述

IBM 为社区提供了 DB2 免费版本 DB2 Express-C,它提供了与 DB2 Express Edition 相同的核心数据特性,为构建和部署应用程序奠定了坚实的基础。


DB2 性能优化是一件较为复杂的综合性的工作 , 需要对问题的根源作全方位的探索和思考。同时也需要较深厚的数据库管理经验与优化知识。这对于初学者来说可能有些勉为其难。但是在很多情况下,随着 DB2 数据库中的数据量的不断增长或者用户数的激增,数据库系统的性能会显著下降,而此时快速定位性能上的瓶颈则至关重要。下面简要地介绍一下 DB2 的调优的一些因素和工具,以及一些原理,使初学者对性能优化能够有一个大致的了解。
DB2 的性能优化可以从三个方面分析:内存,CPU 和 I/O 。
内存因素
在内存方面,主要是考虑缓冲池 (BUFFERPOOL) 的使用。缓冲池是一片用来缓冲从磁盘上读取的数据和索引的内存区域,这些数据和索引信息在缓冲池中进行运算后最终还要写回磁盘。缓冲池的页面大小有四种 (4K,8K,16K,32K),分别对应四种不同页面大小的表空间。缓冲池的大小决定了能够从磁盘上缓冲数据的容量大小。当然缓冲池也不是越大越好,缓冲池过大可能会导致连接数据库的时间过长,因为在连接数据库时要为数据库的缓冲池分配内存空间。可以通过计算缓冲池的命中率来评估缓冲池的使用效率:缓冲池命中率 =(1-(( 数据物理读 + 索引物理读 )/( 数据逻辑读 + 索引逻辑读 ))) *100%,缓冲池命中率越大说明缓冲池的使用效率高。缓冲池命中率太小说明缓冲池太小应当调大。其中的数据物理读,索引物理读以及数据逻辑读和索引逻辑读都可以从缓冲池的快照中获取。
在内存方面要考虑的另外几个重要因素是排序堆 (SORTHEAP),锁列表 (LOCKLIST), 日志缓冲区 (LOGBUFSZ) 。排序堆在查询结果带有排序选项而没有相关索引对应时将会被使用,排序堆太小会产生排序溢出 (Overflowed), 那些在排序堆中装不下的排序数据将会溢出到一个临时表中,这会使性能下降。与 SORTHEAP 参数相关的是 SHEAPTHRES_SHR 和 SHEAPTHRES,SHEAPTHRES_SHR 限制了一个数据库中共享排序的最大内存,SHEAPTHRES 限制了私有排序的最大内存。 LOCKLIST 指的是一个数据库中用来存放锁的内存空间,当这个参数设得过小会导致在锁用光这部分资源后导致锁升级(即多个行锁转化为一个表锁来释放出更多的资源)。这会导致系统的并行性下降,很多应用连接出现挂起,使得系统的性能衰退。所以尽可能调大 LOCKLIST 参数,这里需要指出 LOCKLIST 指的并不是锁的个数,而是以数据库页为单位的一片内存区域(在 32 位系统中每个锁需要 96 个字节,锁上加锁的话每个锁则需 48 个字节。在 64 位系统中每个锁需要 128 个字节,锁上加锁的话每个锁则需 64 个字节)。与 LOCKLIST 参数对应的是 MAXLOCKS 参数,MAXLOCKS 定义的是一个百分数,它指定了一个应用程序所能占用的最大的锁空间占 LOCKLIST 的比例。日志缓冲区 (LOGBUFSZ) 指的是日志在写到磁盘以前用于缓冲的一片内存空间,这样可以减少写日志带来的过多的 I/O 。
从版本 9 以后 DB2 推出了一个新特性自调节内存管理器 (STMM: Self Tuning Memory Manager), 这个特性使得很多内存参数如前面所述的 SORTHEAP,LOCKLIST,LOGBUFSZ 等进行自动调节,当数据库参数 SELF_TUNING_MEM 设为 ON, 这些参数设为 AUTOMATIC 即可以进行自动调整。这样可以节省很多人工调整的时间。
CPU 因素
关于 CPU 因素首先是考虑 DB2 优化器 (OPTIMIZER) 对访问计划 (ACCESS PLAN) 的分析与优化。一般来说,一条 SQL 在执行时首先会被解析,然后进行语义分析,进而重写 SQL, 优化器会对重写过的 SQL 进行基于成本的分析最终选择最有效的访问计划。最终生成可执行代码(执行计划)来执行这条语句。查询访问计划的工具有很多,既有图形化工具 Visual Explain,也有命令 db2exfmt 来格式化解释表 (Explain tables) 中的数据生成 ACCESS PLAN 。还有命令 db2expln 查询 ACCESS PLAN 。
在 DB2 里的优化级别分为九级,缺省是第五级,级别越高优化器分析得程度越深。这个级别有数据库配置参数 DFT_QUERYOPT 决定。并不是级别设得越高性能越好,因为对于一些较为简单的 SQL 语句,如果优化级别过高那么花在优化 SQL 上的时间就会过长,而执行时间相对来说很短,有些得不偿失。在选择访问计划时,索引扫描的效率往往会比表扫描要高,所以索引的优化也是值得注意的。正确的建立索引会使查询性能大幅度的提高。
在 DB2 中连接 (JOIN) 分为三种:嵌套循环连接 (nest-loop join), 合并连接 (merge-join), 散列表连接 (hash-join) 。一般来说效率最低的是嵌套循环连接,这种连接采用的是笛卡儿集,进行多次循环遍历得到结果。而合并连接和散列表连接只进行一次循环遍历,相对来说效率较高。其中散列表连接可以采用多个等式做为条件而合并连接只能采用单个等式作为条件。但是在有索引扫描的情况下嵌套循环连接效率则更高。当优化级别等于零时,连接只能采用嵌套循环连接, 当优化级别大于等于 1 时,连接可以采用合并连接。当优化级别大于 5 时连接可以采用散列表连接。散列表连接要求 SORTHEAP 比较大,因为要为生成散列表准备空间。
在考虑 CPU 因素时还要考虑 CPUSPEED 这个参数,这个参数标明了 CPU 的运行速度,它会帮助优化器评估最好的访问计划。一般来说这个参数设为 -1,优化器将自动计算 CPU 的速度。另外运用多分区的特性可以把一个数据库分布到多台机器上,这样可以充分利用多台机器的 CPU 的资源对应用程序的事务进行并行处理,从而提高数据库的性能。
I/O 因素
关于 I/O 因素要考虑以下几个方面:首先是磁盘的 I/O, 为了能够最大化磁盘的 I/O 可以把数据,索引以及日志分别放在不同的硬盘上。因为在一个事务中数据和索引可能需要同时访问,而在事务提交时,数据和日志要同时写入磁盘,而且有可能索引也要同步维护,所以将它们放在不同的硬盘上可以使它们的读写并行运行,从而不致使磁盘成为瓶颈。同时选择数据库管理表空间 (DMS) 要比系统管理表空间 (SMS) 性能要好,因为读写 SMS 需要经过操作系统的 cache 再到缓冲池,而可以采用裸设备的 DMS 则不需要。但是 DMS 相对 SMS 来说维护起来较麻烦。
其次要考虑的是日志文件的大小,当数据库在写事务日志时当一个日志文件写满后会转向另外一个日志文件,这种日志文件的切换会造成操作系统上的开销。所以应当尽量将日志文件大小(LOGFILSIZ)设得大一些,这样可以减少日志文件切换的次数。但是日志文件过大难免会造成一些空间的浪费。
同时也要考虑到隔离级别的因素,在 DB2 中隔离级别分成 4 级:可重复的读,读稳定性,游标稳定性和未提交的读。这四种级别逐个降低。越高的隔离级别越能保证数据完整性,但却会降低并发性,所以应当综合权衡后做出决定。隔离级别可以通过如下命令来改变:
CHANGE ISOLATION TO=CS|RR|RS|UR
在连接方面还要考虑到代理和连接的关系,这也会影响到数据库的并发性,具体信息可以参考资源部分。
最后要考虑的还是关于多分区的特性。在多分区数据库中,一个请求首先传到协调分区,然后由协调分区将请求细分成多个部分发送到其他分区,这样数据可以在各个分区进行并行读写,实现 I/O 最大化。
收起
参与7

查看其它 6 个回答WUJJ0828的回答

WUJJ0828WUJJ0828系统架构师华际信息系统有限公司
案例分析

查询优化案例

接下来这里从一个试验来看一下 DML 操作过程中优化的详细步骤和具体数据。首先看一个查询优化的例子,下面是试验中的建表语句:


CREATE TABLE MCLAIM.T1_DMS (
C11 VARCHAR (10)  NOT NULL ,
  C12 VARCHAR (15)  NOT NULL  ,
  C13 VARCHAR (20)  NOT NULL  ,
  CONSTRAINT C11_PK PRIMARY KEY ( C11)  ) IN DMS_Space;
  
CREATE TABLE MCLAIM.T2_DMS (
C21 VARCHAR (15)  NOT NULL ,
C22 VARCHAR (25)  NOT NULL  ,
C23 VARCHAR (30)  NOT NULL  ,
CONSTRAINT C21_PK PRIMARY KEY ( C21)  ) IN DMS_Space;

CREATE TABLE MCLAIM.T3_DMS (
C31 VARCHAR (10)  NOT NULL ,
C32 VARCHAR (25)  NOT NULL  ,
C33 VARCHAR (35)  NOT NULL  ,
CONSTRAINT C31_PK PRIMARY KEY ( C31)  ) IN DMS_Space;

  


最初的环境没有优化,表空间类型 SMS 表空间,查询的表中没有索引,sortheap 过小等等。在这种情况下执行下列查询语句:

select C12 from TESTOPT.T1_SMS,%SCHEMA%.T2_SMS,%SCHEMA%.T3_SMS
where substr(C12,1,10)=substr(C21,1,10) and C22=C32
order by C12 asc
  


在没有优化的情况下得到的总的执行时间是 653 秒,而经过优化后得到总的执行时间是大概是 15 秒左右。在优化中采用了如下优化步骤:

选择 DMS 表空间。
添加索引:
CREATE UNIQUE INDEX INDEX_C12 on T1_DMS (C12 ASC);
CREATE UNIQUE INDEX INDEX_C22 on T2_DMS (C22 ASC);
CREATE UNIQUE INDEX INDEX_C32 on T2 _DMS (C32 ASC);



增大 sortheap 的大小
执行 runstats
选择适当的优化级别
改进表结构,增加冗余字段。以空间换时间:
ALTER TABLE T1 ADD C12_Red VARCHAR(10);
ALTER TABLE T2 ADD C21_Red VARCHAR(10);
UPDATE T1 SET C12_Red=SUBSTR(C12,1,10);
UPDATE T2 SET C21_Red=SUBSTR(C21,1,10);
  

查询语句变成:
select C12 from TESTOPT.T1_DMS, TESTOPT.T2_DMS, TESTOPT.T3_DMS
where C12_Red=C21_Red and C22=C32 order by C12 asc
  



图 1. 查询操作优化示意图


从图中可以看出选择好的表空间类型 ( 数据库管理表空间 ) 和添加索引会对性能有很大的改善作用。而添加冗余字段对性能的改进作用最大。当然这会涉及表结构的变化,是需要在数据库设计阶段考虑的因素。同时代价是增加磁盘的占用空间。

写入操作优化

接下来是一个写操作的例子(插入)。下面是试验的脚本:


CONNECT TO FFTEST;
CREATE SCHEMA TESTOPT;
DROP TABLE TESTOPT.T3;
CREATE TABLE TESTOPT.T3 (
C31 VARCHAR (10)  NOT NULL ,
C32 VARCHAR (15)  NOT NULL  ,
CONSTRAINT C31_A CHECK ( C31 LIKE 'A%' or C31 LIKE 'a%'));
       
CREATE INDEX TESTOPT.INDEX_C31 on TESTOPT.T3 (C31 ASC);
ALTER TABLE TESTOPT.T3 ADD CONSTRAINT C31_A CHECK (substr(C31,1,1)= ’ a ’
   or substr(C31,1,1)= ’ A ’ )
ALTER TABLE TESTOPT.T3 APPEND OFF;
CONNECT RESET;
  


最初的表没有优化,含有索引,约束等因素,插入 4 万条记录大约花了 68 秒钟,而最终优化后插入 4 万条记录只需 6 秒钟。如下是优化步骤:

去除索引。
去除约束。
在 insert 语句中包括多行。
采用 Append 模式
屏蔽表的日志操作。
采用并行写操作。
采用严格的隔离级别。

图 2. 插入操作优化示意图


从图中可以看出减少索引和约束可以大幅度提高插入性能,而将多条插入语句合并成一行产生的效果更加明显。

性能调优注意事项

为了得到高性能将缓冲池调得过大,导致数据库连不上。这对没有经验的用户来说可能是个灾难,这意味着数据库可能要重建。最初我们曾经犯过这样的错误。现在可以通过调节 DB2 注册参数 DB2_OVERRIDE_BPF 来设置缓冲池的大小,从而能够再次连接数据库。当然最好将 STMM 激活,使内存能够自动调整。
往往忽视 runstats 和 reorg 的作用,我们发现不止一个的性能问题,都是由于优化器选择了错误的 access plan 导致系统整体性能下降。而对外显示的则不光是 SQL 执行慢,同时也能会表现出 I/O 瓶颈或系统响应时间长。这往往会误导我们去分析其他地方。但究其根源,很多时间是由于优化器的错误。这些问题往往在重新执行 runstats 和 reorg 之后就解决了。所以这两个命令也要特别注意。
在进行数据加载的时候往往忽略了索引因素,导致性能加载性能下降。我们遇到过这样的一个例子,一张表导入 1000 条记录花了 5 分钟,检查了很多配置找不到原因,最后发现这张表上有 1 个主键,还有 4 个外键。将他们删除后重新导入只花了几秒钟。所以在进行 load 或者是 insert 的时候尽量将主外键或相关索引删除,加载完成后重建相关索引。主外键尽量通过加载程序来保证它的数据完整性。这一点往往会被忽略,所以在加载数据前先检查一下所有表的索引状态及引用关系。
在修改 db2 参数的时候,一次最好修改一个参数,然后看看效果,在调节其他参数。否则一次多个参数,调好了也没弄清楚是哪个参数起的作用。下次还得全部来一遍。还要注意,并非所有参数都是越大越好,有时可能会适得其反。
注意索引的试用,优化好的索引对查询语句性能的提高往往会产生数十倍的性能改进。所以,调优前可以先察看一下相关语句的索引利用情况。这可以通过察看 SQL 语句和执行计划,看一下已有索引是否被利用起来了或是否需要建立新的索引。这往往比 DB2 系统调优更重要。但切记考虑插入操作,索引也会降低插入的性能。这一点要综合考虑。
由于 XML 数据可以跨页存储,在设计 XML 数据库时要尽可能的使用较大的数据页,这样可以避免 XML 数据跨页查询,以提高查询性能。
采用表分区:有这样一个例子:客户有一张表的数据量非常大,每天都会产生大约 30 万条记录,同时每天都会删除五天前的记录,所以此表大概有 150 万条记录,现在客户在每天的第一次查询时要重新对表进行索引(因为晚上会产生很多数据,所以新增加的数据都没有建索引),导致响应非常慢!对于这种问题,后来采用了表分区,用 6 个分区表来分别装载原来 6 天的数据。所以查询和插入都只涉及一张表,所以响应速度得到大幅度提高。
了解 CHNGPGS_THRESH 参数,是缓冲池写日志的阀值。有一个例子,在创建索引时比较慢,经过检查发现 CHNGPGS_THRESH 参数过大,造成每次写日志的时候数据量过大,造成 I/O 瓶颈,适当减小这个参数值,可以增加写日志的次数,但数减少每次写日志的数据量,这对于大缓冲池里的大表上创建索引时很有效的。
在导入数据时尽量采用 load, 少用 import, 我们做过统计,用 import 花费 10 分钟的数据,用 load 大概只需要 1 分钟,这大大提高了工作效率。
注意 db2diag.log 的大小,当这个文件很大的时候,数据库的所有操作,包括停启 db2 都会特别的慢,有时甚至挂起。所以要经常看看这个文件的大小,过大时最好删掉,重启 db2 。当然 DIAGLEVEL 不要设得太高,除非为了诊断某个问题获得更多信息,一般默认的 3 足够了。
互联网服务 · 2009-06-12
浏览1320

回答者

WUJJ0828
系统架构师华际信息系统有限公司
擅长领域: 数据库服务器AIX

WUJJ0828 最近回答过的问题

回答状态

  • 发布时间:2009-06-12
  • 关注会员:0 人
  • 回答浏览:1320
  • X社区推广