技术开发 频道

调优DB2 v8.1及其数据库的非常好的实践

概要注册表配置

DB2 概要注册表变量通常要影响优化器和 DB2 引擎本身的行为。虽然概要注册表变量有很多,但是其中的大部分都有其非常特定的用途,因而在大部分的 DB2 环境中都不会用到。下面是一些常用的概要注册表变量。

表 2列出了用于概要注册表一些基本管理命令:

表 2. 概要注册表管理

命令描述
db2set -all列出所有当前设置的 DB2 注册表变量
db2set -g | -i variable= value设置指定的 DB2 注册表变量,使其或者处于全局(-g)级,或者处于实例(-i)级

注意:在变量和值之间不要有空格,否则变量又会重新被设置成缺省值。

DB2_PARALLEL_IO
这将帮助促使对驻留在磁盘阵列上的任何表空间采用并行访问。如果所有表空间都在磁盘阵列上,则将该变量设置成等于 *。如果只有一些表空间在磁盘阵列上,则使用 "db2 list tablespaces" 检索这些表空间的 ID,并将该变量设置成这些 ID(使用逗号将各 ID 分隔开)。为获得非常好的性能,应确保表空间的预取大小明显大于它的区段大小。

DB2_EVALUNCOMMITTED
缺省值是 OFF,如果将其改为 ON,则会将锁操作推迟到谓词演算。启用这个变量对于减少从 Oracle 移植过来的应用程序中存在的锁争用十分有用。

DB2_SKIPDELETED
缺省值是 OFF,如果将其改为 ON,则允许使用 CS 或 RS 的语句略过索引中被删除的键以及表中被删除的行。同样,启用这个变量对于减少从 Oracle 移植过来的应用程序中存在的锁争用十分有用。

DB2_HASH_JOIN
缺省值是 Enabled。如果禁用 DB2_HASH_JOIN(NO),则 OLTP 可能受益。

(AIX): DB2_FORCE_FCM_BP
缺省值是 NO。如果使用了 DB2 的 Database Partitioning Feature (DPF) 功能,并且有多个逻辑分区,那么将该变量设置为 YES 可以改善分区间的通信,代价是可供缓冲池使用的共享内存段要少掉一个。如果没有使用数据库分区功能,则应使用 NO 值。

(AIX 4.3) DB2_MMAP_READ 和 DB2_MMAP_WRITE
缺省情况下两者都处于启用状态的。如果使用 AIX 4.3,32 位的 DB2,并且内存会限制增加缓冲池的大小,那么应将此变量设置成 OFF,以便多释放一个内存段。这样大约可以释放 256 MB 的共享内存(这样就可以将其中一部分用于缓冲池)。可以进行一些测试,以确信这一更改的确提升了性能,因为有时候对磁盘使用内存映射的读和写比起增加缓冲池大小来可以获得更好的性能,虽然这种做法并不常见。

DB2 v8 Documentation:

  • Reference ==> Registry and environment variables
     

通过配置避免运行时错误

应用程序开始运行的时候,通常会暴露出与某些配置参数有关的问题。如果在应用程序运行期间没有收到任何错误或警告信息,那么就是安全的。如果收到了这样的信息,那么请参阅本文后面对 数据库管理器和数据库配置参数管理的讨论。如果没有足够的内存来处理 SQL,下面的一些配置参数就会出问题:

MON_HEAP_SZ (DBM)
这是为数据库系统监视器(system monitor)数据分配的内存数量。当执行诸如快照监视或激活一个事件监视器之类的数据库监控活动时,就要从监视器堆中分配内存。如果没有足够的可用内存,并且 DB2 返回一个错误,则可以试着将这个值设为 256。如果还是遇到错误,一次一次地增加 256,直到错误消失。

QUERY_HEAP_SZ (DBM)
这是为了将每个查询存储到代理的私有内存时可以分配的最大内存量。查询堆还可用于为块游标(blocking cursor)提供内存分配。查询堆的大小必须大于或等于 ASLHEAPSZ。如果收到 DB2 返回的一个错误,表明性能可能不是最优,而处于最低状态,那么可将此参数设为至少大于 ASLHEAPSZ 的五倍,这样就允许查询大于 ASLHEAPSZ,并且为 3 个或 4 个并发的块游标足够的内存。

MAXAPPLS (DB)
该参数指定可以连接(包括本地连接和远程连接)到一个数据库的并发的应用程序的最大数目。在绝对最小值情况下,将此参数设置为 >= (用户连接的数量)。要了解详细信息,请参阅本文后面对 MAXAGENTS的讨论。

STMTHEAP (DB)
语句堆用于在 SQL 语句的编译期间作为编译器的工作区。对于每一条要处理的 SQL 语句,都要从该区域分配和释放空间。如果收到警告信息或错误信息,那么可以按 256 逐次增加,直到错误消失。

APPLHEAPSZ (DB)
应用程序堆是供数据库管理器代表某个特定代理使用的私有内存。当代理或子代理要为应用程序而初始化时,就要从这个堆中分配内存,并且所分配的内存数量是处理请求时所需的最小内存量,如果需要更多的内存,则最多可以从堆中分配由该参数指定的一个最大值那么多的内存。按 256 逐次增加,直到错误消失。

为提高性能进行快照监视

使用快照监视来识别数据库在一段时间里的行为,显示一些诸如内存使用情况和锁的获得过程之类的信息。监控是用于微调配置和识别问题(例如语句执行时间较长)的一种方法。如果已经使用了 Configuration Advisor,那么这里可能无法在性能上获得什么好处。

要收集供分析的数据,最容易的方法是在应用程序运行的时候用一个脚本来执行抽样的快照监视。像 清单 3中或者 清单 4中显示的脚本将会收集您进入下一步之前所需的所有信息。首先在 60 秒的一段时间内运行该脚本,其中有几次间歇;这样应该可以对应用程序行为的一个较好的抽样,并且不会有太多的信息要处理。

清单 3. getsnap.ksh (UNIX)

#!/usr/bin/ksh
#  take a snapshot after specified sleep period for a number of iterations
#  parameters: (1) database name
# 	       (2) directory for output
#              (3) interval between iterations (seconds)
#              (4) maximum number of iterations
#	       
#  Note: You may receive an error about the monitor heap being too small. You may 
#        want to set mon_heap_sz to 2048 while monitoring.
if [ $# -ne 4 ]
  then echo "4 parameters required: dbname output_dir sleep_interval iterations"; exit
fi
dbname=$1
runDir=$2
sleep_interval=$3
iterations=$4
stat_interval=3
stat_iterations=$(($sleep_interval/$stat_interval))
if [[ -d $runDir ]]; then
   echo "dir: $runDir already exists, either remove it or 使用 another directory name"
   exit
fi
mkdir  $runDir
cd     $runDir
db2 update monitor switches using bufferpool on lock on sort on statement on \\
    table on uow on
# repeat the snapshot loop for the specified iterations
let i=1
while [ i -le $iterations ] 
  do
    if [ $i -le 9 ]
    then 
      i2="0$i"
    else
      i2="$i"
    fi 
    echo "Iteration $i2 (of $iterations) starting at `date`"
    vmstat $stat_interval $stat_iterations > vmstat_$i2
    iostat $stat_interval $stat_iterations > iostat_$i2
    db2 -v reset monitor all
    sleep $sleep_interval
    db2 -v get snapshot for dbm > snap_$i2
    db2 -v get snapshot for all on $dbname >> snap_$i2
    echo "Iteration $i2 (of $iterations) complete at `date`"
    let i=$i+1
  done 
db2 update monitor switches using bufferpool off lock off sort off statement off \\
    table off uow off 
db2 terminate

 

清单 4. getsnap.bat (Windows)

@echo off
REM
REM  take a snapshot after specified sleep period for a number of iterations
REM  parameters: (1) database name
REM    	         (2) file name id
REM              (3) interval between iterations (seconds)
REM              (4) maximum number of iterations
REM 	       
REM   Note: You may receive an error about the monitor heap being too small. You may 
REM         want to set mon_heap_sz to 2048 while monitoring.
:CHECKINPUT
IF ""=="%4" GOTO INPUTERROR
GOTO STARTPRG
:INPUTERROR
echo %0 requires 4 parameters: dbname filename_id sleep_interval iterations
echo e.g. "getsnap.bat sample 0302 60 3"
GOTO END
:STARTPRG
SET dbname=%1
SET fileid=%2
SET sleep_interval=%3
SET iterations=%4
db2 update monitor switches using bufferpool on lock on sort on statement on table on uow on
REM repeat the snapshot loop for the specified iterations
SET i=1
:SNAPLOOP
    IF %i% LSS 10 SET i2=0%i%
    IF %i% GTR 9 SET i2=%i%
    echo Starting Iteration %i2% (of %iterations%) 
    db2 -v reset monitor all
    sleep %sleep_interval%
    db2 -v get snapshot for dbm > snap%i2%_%fileid%
    db2 -v get snapshot for all on %dbname% >> snap%i2%_%fileid%
    echo Completing Iteration %i2% (of %iterations%)
    SET /a i+=1
    IF %i% GTR %iterations% GOTO ENDLOOP
    GOTO SNAPLOOP
:ENDLOOP
db2 update monitor switches using bufferpool off lock off sort off statement off table off uow off 
db2 terminate
:END

 

注意,这两个脚本在行为上稍有不同,但是都可以产生所需的快照输出。

在后面的一些小节中,快照监视可用作寻找 DBM 和 DB 配置参数的最优设置的一种方式。

DB2 v8 Documentation:

  • Reference ==> System monitor ==> Snapshot monitor

动态 SQL 语句

清单 3清单 4中显示的脚本将发出一个 "get snapshot for all on dbname" 命令,该命令包括 "get snapshot for dynamic SQL on dbname" 命令的所有输出。如果您发现不会捕获很多的 SQL 语句,那么可以增加监控的历时。一条语句的输出的 "Dynamic SQL Snapshot Result" 部分看上去如 清单 5所示:

清单 5. 示例动态 SQL 快照

      Dynamic SQL Snapshot Result 
 Database name                      = SAMPLE 
 Database path                      = C:\\DB2\\NODE0000\\SQL00003\\
         Number of executions           = 1
 Number of compilations             = 1  
 Worst preparation time (ms)        = 1624  
 Best preparation time (ms)         = 1624  
 Internal rows deleted              = 0  
 Internal rows inserted             = 0  
         Rows read                      = 41
 Internal rows updated              = 0  
 Rows written                       = 0  
 Statement sorts                    = 0  
         Total execution time (sec.ms)  = 0.134186
 Total user cpu time (sec.ms)       = 0.000000  
 Total system cpu time (sec.ms)     = 0.000000  
         Statement text                 = select * from sales
  		...
      

 

您可以看到,在输出中可以搜索一些很有用的字符串。

"Number of executions"- 可以帮助您找到应该调优的那些重要语句。它对于帮助计算语句的平均执行时间也很有用。

对于执行时间很长的语句,单独执行一次或许对系统要求不多,但是累加起来的结果就会大大降低性能。应尽量理解应用程序如何使用该 SQL,或许只需对应用程序逻辑稍微重新设计一下就可以提高性能。

看看是否可以使用参数标记(parameter marker),以便只需为语句创建一个包,这一点也很管用。参数标记 可用作动态准备的语句(生成访问计划时)中的占位符。在执行的时候,就可以将值提供给这些参数标记 marker,从而使语句得以运行。

例如,要搜索执行得最频繁的语句:

UNIX:

grep -n " Number of executions" 
        snap.out | grep -v "= 0" | sort -k 5,5rn | more
      

 

Windows:

findstr /C:" Number of executions" 
        snap.out | findstr /V /C:"= 0"
      

 

"Rows read"- 可帮助识别读取行数最多的 Dynamic SQL 语句。如果读取的行数很多,通常意味着要进行表扫描。如果这个值很高,也可能表明要进行索引扫描,扫描时选择性很小,或者没有选择性,这跟表扫描一样糟糕。

您可用使用 Explain 来查看是否真的如此。如果有表扫描发生,那么可以对表执行一次 RUNSTATS,或者将 SQL 语句提供给 DB2 Design Advisor,以便令其推荐一个更好的索引,以此来进行弥补。如果是选择性很差的索引扫描,或许需要一个更好的索引。可以试试 Design Advisor。

grep -n " Rows read" 
        snap.out | grep -v "= 0" | sort -k 5,5rn
      

 

findstr /C:" Rows read" 
        snap.out | findstr /V /C:"= 0"
      

 

"Total execution time" - 这是将语句每次执行时间加起来得到的总执行时间。我们可以很方便地将这个数字除以执行的次数。如果发现语句的平均执行时间很长,那么可能是因为表扫描和/或出现锁等待(lock-wait)的情况。索引扫描和页面获取导致的大量 I/O 活动也是一个原因。通过使用索引,通常可以避免表扫描和锁等待。锁会在提交的时候解除,因此如果提交得更频繁一些,或许可以弥补锁等的问题。

grep -n " Total execution time" 
        snap.out | grep -v "= 0.0" | sort -k 5,5rn | more
      

 

findstr /C:" Total execution time" 
        snap.out | findstr /V /C:"= 0.0" |sort /R
      

 

"Statement text"显示语句文本。如果注意到了重复的语句,这些语句除了 WHERE 子句中谓词的值有所不同以外,其他地方都是一致的,那么就可以使用参数标记,以避免重新编译语句。这样可以使用相同的包,从而帮助避免重复的语句准备,而这种准备的消耗是比较大的。还可以将语句文本输入到 Design Advisor 中,以便生成最优的索引。

grep -n " Statement text" 
        snap.out | more
      

 

findstr /C:"Statement text" 
        snap.out
      

0
相关文章