Chinaunix首页 | 论坛 | 博客
  • 博客访问: 1016104
  • 博文数量: 146
  • 博客积分: 3444
  • 博客等级: 中校
  • 技术积分: 1602
  • 用 户 组: 普通用户
  • 注册时间: 2009-01-21 15:18
文章分类

全部博文(146)

文章存档

2014年(9)

2013年(3)

2012年(6)

2011年(44)

2010年(38)

2009年(46)

分类:

2010-08-12 15:36:27

使用语句事件监视器调优 DB2 通用数据库
 
 
发布者:IBM  日期: 2003-03-01 00:00:00 浏览次数:28 (共有0条评论) 查看评论 | 我要评论
 
级别: 初级
Ramakrishna Kolluru, SeeCommerce.com

2003 年 3 月 01 日
为了调优 SQL 以及确定应该创建什么索引来提高性能,本文描述了一项技术,用于分析 DB2 通用数据库语句事件监视器的输出。此外,本文还提供了一个样本程序。
本文专门针对 IBM? DB2? Universal Database? Linux、UNIX? 和 Windows? 版。
简介
对于数据库管理员,调优数据库常常是一项挑战。调优应用程序是一种方法,但在大多数生产系统中 DBA 很少甚至不能更改源代码,因此限制了他们调优应用程序的能力。这在 DBA 使用第三方工具时尤为如此。所以,通常最有效的调优方法是解决问题的根源,即从 SQL 语句本身入手。通常通过查找哪些 SQL 语句消耗的资源最多来获得最佳性能,然后决定采取一定的措施来减少资源消耗。
通常,在第一次安装数据库时,会将其性能调至最优,但随着时间的流逝,一些常用的东西开始变得越来越慢。这在拥有大量数据的系统(譬如决策支持系统)中尤为如此。用户开始看到如锁升级、全表扫描以及排序这样的因素造成性能下降,这些操作往往会迫使系统访问磁盘而不是访问内存。当出现这种情况时,最好检查一下 SQL,看看可以做哪些改进。
本文旨在解决的问题是:针对通常的活动,调优正在用于访问数据库的 SQL。为了简化如何监控应用程序中 SQL 语句的问题,我编写了一个 Java 程序 http://www.ibm.com/developerworks/cn/data/library/techarticles/0303kolluru/DB2Trace.java ,帮助您在使用 DB2 通用数据库事件监视器时,确定哪些 SQL 语句消耗的资源最多。
DB2 事件监视器是 DB2 通用数据库 Linux、UNIX 和 Windows 版所带的工具。每当数据库中发生所指定的事件,该工具就将数据写到文件或命名管道,它是一种用来跟踪数据库中特定活动的方式。 http://www.ibm.com/developerworks/cn/data/library/techarticles/0303kolluru/DB2Trace.java 程序从语句事件监视器获取输出,然后将其插入到数据库的 DB2TRACE 表中。然后,可以使用 SQL 查询来分析数据,为有问题的 SQL 语句创建相应的索引,或者另外做一些更改以提高性能。
准备好之后,现在 下载代码,自己尝试一下。
 
 

 
 
 
先决条件
本文所描述的程序用 DB2 通用数据库企业版 V7.2.2 和 JAVA 1.2.2 测试过。为了支持 JDBC 2.0,JAVA 版本应为 1.2 或更高。
虽然在 UNIX 上测试过该程序,但最好还是在 Windows 上运行该程序,这样肯定不需要做任何更改。注:下面所显示的命令是针对 UNIX 命令 shell 环境,对于 Windows 环境,需要做适当的修改。
 
 

 
 
 
运行事件监视器
首先,必须创建事件监视器,运行监视器来收集将要分析的数据。在下面这些步骤中,用您自己的数据库名替代 dbname,用您自己的用户标识替代 username,用您自己的密码替代 password。注: rkmon是该示例所使用的事件监视器的名称,您可以用其它任何名称来替代它。
打开一个新的 DB2 命令行处理器会话,然后执行以下 DB2 UDB 命令: db2 => connect to
            dbname user
            username using
            password
db2 => update monitor switches using statement on
db2 => create event monitor rkmon for statements write to file '/tmp'
db2 => set event monitor rkmon state=1
          

使该会话一直处于打开状态,直到这些数据库活动完成。请确保 /tmp 目录有足够大的空间来保存跟踪文件。这里选择 /tmp 目录是因为所有用户都可以访问该目录;但也可以选择使用其它目录(请确保对于该目录,DB2 有访问权限)。目录的大小取决于用户想要捕获的 SQL 语句的数目。一开始,最好设为 500 MB。
执行正常的数据库活动,直到您想监控的时段结束。这一监控阶段可以是问题产生时期,也可以是通常的数据库活动过程。在 /tmp 目录下,您应该可以看到一组扩展名为“ .evt ”的文件。这些文件就是您的事件监视器文件。
回到在步骤 1 中所打开的会话,然后发出以下语句:
db2 => set event monitor rkmon state=0
db2 => terminate
 
如果要删除监视器可用 drop event monitor rkmon

在平常的命令提示符下,执行以下命令: $ db2evmon -path /tmp > sqltrace.txt
 
在单个文件 sqltrace.txt 中会有所有已捕获的 SQL 语句及其细节。

 

 
 
 
现在您已经在 sqltrace.txt 文件中收集好数据。下一步将使您能分析这些数据。
将 DB2Ttrace.java 程序下载 至 /tmp 目录。下面这个清单 1 是 http://www.ibm.com/developerworks/cn/data/library/techarticles/0303kolluru/DB2Trace.java 程序的副本。 
清单 1. http://www.ibm.com/developerworks/cn/data/library/techarticles/0303kolluru/DB2Trace.java
/*(c) Copyright IBM Corp. 2003  All rights reserved.                 */
/*                                                                   */
/*This sample program is owned by International Business Machines    */
/*Corporation or one of its subsidiaries ("IBM") and is copyrighted  */
/*and licensed, not sold.                                            */
/*                                                                   */
/*You may copy, modify, and distribute this sample program in any    */
/*form without payment to IBM, for any purpose including developing, */
/*using, marketing or distributing programs that include or are      */
/*derivative works of the sample program.                            */
/*                                                                   */
/*The sample program is provided to you on an "AS IS" basis, without */
/*warranty of any kind.  IBM HEREBY  EXPRESSLY DISCLAIMS ALL         */
/*WARRANTIES EITHER EXPRESS OR IMPLIED, INCLUDING, BUT NOT LIMITED TO*/
/*THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTIC-*/
/*ULAR PURPOSE. Some jurisdictions do not allow for the exclusion or */
/*limitation of implied warranties, so the above limitations or      */
/*exclusions may not apply to you.  IBM shall not be liable for any  */
/*damages you suffer as a result of using, modifying or distributing */
/*the sample program or its derivatives.                             */
/*                                                                   */
/*Each copy of any portion of this sample program or any derivative  */
/*work,  must include a the above copyright notice and disclaimer of */
/*warranty.                                                          */
/*                                                                   */
import  java.io.*;
import  java.sql.*;
/**
 * DB2Trace program reads the output from the db2event monitor
 * and inserts the data into a database.
 *
 * Creation Date: January 15 2003.
 */
class DB2Trace {
    /**
     * Usage: java DB2Trace sqltrace.txt jdbc:db2:db2mwh userid
     * password
     * sqltrace.txt is the input file
     * jdbc:db2:db2mwh is the database jdbc url connection
     * username is the user ID
     * password is the password
     * @param args[]
     * @exception IOException, SQLException
     */
    public static void main (String args[]) throws IOException,
SQLException {
        FileWriter fw = new FileWriter("DB2Trace.sql");
        PrintWriter pw = new PrintWriter(fw);
        BufferedReader in = new BufferedReader(new
FileReader(args[0]));
        String s = "";
        String sqlString = "";
        boolean textYes = false;
        int exists = 0;
        COM.ibm.db2.jdbc.app.DB2Driver driver = new
COM.ibm.db2.jdbc.app.DB2Driver();
        java.sql.DriverManager.registerDriver(driver);
        Connection conn =
java.sql.DriverManager.getConnection(args[1], args[2],
                args[3]);
        Statement stmt = conn.createStatement();
        ResultSet rset = stmt.executeQuery("SELECT COUNT(*) FROM
SYSCAT.TABLES WHERE TABSCHEMA=USER AND "
                + "TABNAME='DB2TRACE'");
while (rset.next()) {
            exists = rset.getInt(1);
        }
        if (exists > 0)
            stmt.executeUpdate("DROP TABLE DB2TRACE");
        stmt.executeUpdate("CREATE TABLE DB2TRACE( OPERATION
VARCHAR(30),SQLTXT VARCHAR(32000),"
        + "STARTTIME VARCHAR(30),STOPTIME VARCHAR(30) ,"
+ "EXECTIME VARCHAR(20),"
                + "USRCPU   VARCHAR(20)," + "SORTS   
VARCHAR(20)," + "TOTSORTTIME VARCHAR(20)) IN TEST ");
        stmt.executeUpdate("CREATE INDEX DB2TRACE_CPU ON
DB2TRACE(USRCPU)");
        PreparedStatement p = conn.prepareStatement("INSERT INTO
DB2TRACE(OPERATION,SQLTXT,EXECTIME,"
                              +"
STARTTIME,STOPTIME,USRCPU,SORTS,TOTSORTTIME)
    VALUES(?,?,?,?,?,?,?,?)");
        while ((s = in.readLine()) != null) {
            if (s.startsWith("  Operation: ")) {
                p.setString(1, s.substring(13, s.length()));
            }
            if (s.startsWith("  Text     :")) {
                textYes = true;
                p.setString(2, s.substring(13, s.length()));
            }
            if (s.startsWith("  Exec Time:")) {
                p.setString(3, s.substring(14, s.length() - 7));
            }
            if (s.startsWith("  Start Time: ")) {
                p.setString(4, s.substring(14, s.length()));
            }
            if (s.startsWith("  Stop Time:  ")) {
                p.setString(5, s.substring(14, s.length()));
            }
            if (s.startsWith("  User CPU:")) {
                p.setString(6, s.substring(13, s.length() - 7));
            }
            if (s.startsWith("  Sorts:")) {
                p.setString(7, s.substring(8, s.length()));
            }
            if (s.startsWith("  Total sort time:")) {
                p.setString(8, s.substring(18, s.length()));
                if (textYes == true) {
                    p.executeUpdate();
                    textYes = false;
                }
            }
        }
        pw.close();
        stmt.close();
        p.close();
    }
}
 

按如下编译该程序: $ javac -classpath /export/home/seecomm/sqllib/java/db2java.zip:. http://www.ibm.com/developerworks/cn/data/library/techarticles/0303kolluru/DB2Trace.java
 

注:在该示例中,使用了 JDBC 2.0。使用了 sqllib/java12 目录下的 db2java.zip 。缺省情况下,DB2 V8 使用 JDBC 2.0;然而,对于 DB2 V7,运行文件 usejdbc2.bat (Windows)或 usejdbc2 (UNIX)。
在该示例中,所使用的应用程序驱动程序需要将该数据库编目在 DB2 数据库目录中。这个应用程序驱动程序或胖客户机属于 JDBC 的第 2 类驱动程序。这意味着必须在客户的工作站上安装应用程序开发客户机或 CAE。

请确保创建了 TEST 表空间(其页面为 32 KB)、用于排序的系统临时表空间(其页面为 32 KB)以及与这些表空间相关联的缓冲池(其页面为 32 KB)。在运行该程序之前,应该先创建这些表空间和缓冲池。用以下的 DB2 命令创建表空间和缓冲池: CREATE Bufferpool TESTBP SIZE 1000 PAGESIZE 32 K
 

(先停止实例,然后再启动实例,从而激活该缓冲池,并使它与表空间相关联。)
CREATE REGULAR TABLESPACE TEST PAGESIZE 32 K  MANAGED BY
SYSTEM  USING ('/export/seecomm/') EXTENTSIZE 16 OVERHEAD
24.1 PREFETCHSIZE 32 TRANSFERRATE 0.9 BUFFERPOOL TESTBP
 

现在准备运行该程序: $cd /tmp
$ java -classpath
/export/home/seecomm/sqllib/java/db2java.zip:.  DB2Trace
sqltrace.txt jdbc:db2:db2mwh username password
 

sqltrace.txt 是输入文件。
jdbc:db2:db2mwh 是这个数据库的 JDBC URL 连接。
username 是用户标识。
password 是密码。
在这一步,每条 SQL 语句的 SQL 文本、执行时间、启动时间、停止时间、用户 CPU 时间、排序以及总排序时间都被捕捉到数据库表 DB2TRACE 中。
 
 

 
 
 
分析输出
由于 DB2Trace 程序已经在数据库表(DB2TRACE)中存储了所需要的信息,因此可以查询该表以确定“讨厌”且耗时的 SQL 语句。
需要确定四类 SQL 语句。在执行以下查询以确定这些语句之前,在数据库配置参数中,至少要为应用程序堆大小( applheapsz )分配 256 个页面。
按照执行时间降序排列执行耗时最长的 SQL 语句。为了确定这些语句,使用下面的 SQL SELECT 语句: select sqltxt, exectime "ExecutionTime(sec)"  from db2trace
where operation not in ('Static Commit',
'Static Rollback', 'Prepare', 'Open',
'Describe', 'Compile') 
order by decimal (exectime) desc
fetch first 10 rows only
 

按照频率降序排列执行次数最多的 SQL 语句。可以用下面这条查询来确定这些语句: select distinct(sqltxt),count(*) Count from db2trace
where operation not in ('Static Commit', 'Static Rollback',
'Prepare', 'Open', 'Describe', 'Compile')
group by sqltxt
order by count(*)desc
fetch first 10 rows only
 

按照 CPU 时间降序排列最耗 CPU 时间的 SQL 语句。用下面这条查询来确定这些语句: select sqltxt ,usrcpu "UserCPU(sec)" from db2trace
where operation not in ('Static Commit',
'Static Rollback', 'Prepare', 'Open',
'Describe', 'Compile')
order by usrcpu desc
fetch first 10 rows only
 

按照总排序时间降序排列排序时间最长的 SQL 语句。用下面这条查询找到这些语句: select sqltxt ,totsorttime "TotalSortTime(ms)" from db2trace
where operation not in ('Static Commit',
'Static Rollback', 'Prepare', 'Open',
'Describe', 'Compile')
order by decimal(totsorttime) desc
fetch first 10 rows only
 

捕获每一类中的 SQL 语句,并将它们放在 tune.sql 文件中。将下面这行插入到该文件中,这样可以更改工作负载中每条语句的执行频率: --#SET FREQUENCY
 
 
这里的 表示随后要执行 SQL 语句的次数。您的 tune.sql 文件类似于这样: --#SET FREQUENCY 100
SELECT COUNT (*) FROM EMPLOYEE;
SELECT * FROM EMPLOYEE WHERE LASTNAME='HAAS';
--#SET FREQUENCY 1
SELECT AVG (BONUS), AVG (SALARY) FROM EMPLOYEE
GROUP BY WORKDEPT ORDER BY WORKDEPT;
 
 
将这些 SQL 语句复制到 tune.sql 之后,检查任何 SQL 语句的 WHERE 子句中是否具有参数标志符(?)。将参数标志符改为适当的数据类型值,以便在没有任何错误的情形下执行 SQL 语句。
为了确定哪些索引可能提高性能,按如下执行索引顾问程序: $cd /tmp
$db2advis -d test -i tune.sql -t 0 -o tuneidx.sql
 
 
所有推荐的索引将放置在文件 tuneidx.sql 中。编辑该文件,在文件开始处添加一条连接语句: connect to dbname user userid using password;
 
 
在该文件末尾添加下面这行: terminate;
 
 
现在可以运行该文件以创建推荐的索引: $db2 -tf tuneidx.sql -z tuneidx.log
 
其中, tuneidx.log 捕获 tuneidx.sql 的所有输出。
 
 

 
 
 
结束语
现在,数据库的性能与原来应该大不相同。可以将 DB2TRACE 表中所收集的统计信息输入到电子表格中,这些信息将有助于您更好地了解 SQL 语句到底在使用哪些资源。对 SQL 语句进行调优之后,为了达到更佳性能,还可以调优数据库和数据库管理器参数。
 
 

 
 
 
下载代码
描述 文件类型 文件大小 下载方式
http://www.ibm.com/developerworks/cn/data/library/techarticles/0303kolluru/DB2Trace.java java 5 KB HTTP  
我应该选择哪种下载 方式?
 下载 FAQ
 

关于作者
 
  Ramakrishna Kolluru 是位于加利福尼亚州帕洛阿尔托的 SeeCommerce.com 的高级数据库工程师。他通过了 Oracle 9i 和 DB2 7.1 的 DBA 认证。SeeCommerce 是供应链性能管理方面的佼佼者。可以通过 与他联系。
 
 
阅读(1204) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~