往事如烟,人生如梦;生在沙场,岂甘寂寞。

发布新日志

  • 数据库 db2 导入导出-常用命令

    2009-02-02 17:47:17

     


    DB2安装启动







    服务中启动不了,可用command启动并查看windows系统的日志。





    1.启动数据库
      db2start
    2.停止数据库
      db2stop
    3.连接数据库
    运行 db2命令之前要先运行db2cmd!
    db2 connect to oyd user db2 using pwd

    4.管理功能(控制中心等)的启动
      db2admin start/stop


    db2start或从服务启动都存在问题,请手工删除相关进程。






    导入导出基本概念

    数据移动的文件格式有四种
    在讲解命令之前,首先介绍一下文件的格式,用于DB2数据移动的文件格式有四种:
    1. ASC——非定界ASCII文件,是一个ASCII字符流。数据流中的行由行定界符分隔,而行中的每一列则通过起始和结束位置来定义。例如:
    10 Head Office 160 Corporate New York
    15 New England 50 Eastern Boston
    20 Mid Atlantic 10 Eastern Washington
    38 South Atlantic 30 Eastern Atlanta
    42 Great Lakes 100 Midwest Chicago
    51 Plains 140 Midwest Dallas
    66 Pacific 270 Western San Francisco
    84 Mountain 290 Western Denver
    2. DEL——定界ASCII文件,也是一个ASCII字符流。数据流中的行由行定界符分隔,行中的列值由列定界符分隔。文件类型修饰符可用于修改这些定界符的默认值。例如:
    10,"Head Office",160,"Corporate","New York"
    15,"New England",50,"Eastern","Boston"
    20,"Mid Atlantic",10,"Eastern","Washington"
    38,"South Atlantic",30,"Eastern","Atlanta"
    42,"Great Lakes",100,"Midwest","Chicago"
    51,"Plains",140,"Midwest","Dallas"
    66,"Pacific",270,"Western","San Francisco"
    84,"Mountain",290,"Western","Denver"
    3. WSF——(work sheet format)为工作表格式,用于与Lotus系列的软件进行数据交换。
    4. PC/IXF——是集成交换格式(Integration Exchange Format,IXF)数据交换体系结构的改编版本,由一些列可变长度的记录构成,包括头记录、表记录、表中每列的列描述符记录以及表中每行的一条或多条数据记录。PC/IXF 文件记录由包含了字符数据的字段组成。


    del格式文件
    例一:把Org表中的所有数据导出到文件C:\ORG.TXT中。
    Export to c:\org.txt of del select * from org
    其中,of del表示导出到的文件的类型,在本例中导出到一个非定界文本文件中;后面的select * from org是一个SQL语句,该语句查询出来的结果就是要导出的数据。
    例二:改变del格式文件的格式控制符
    export to c:\staff.txt of del modified by coldel$ chardel'' decplusblank select * from staff
    在该例中,modified子句用于控制各种符号,coldel表示字段之间的间隔符,默认情况为逗号,现在改为$号;chardel表示字符串字段用什么符号引用,默认情况下为一对双引号括起来,现在改为用一对单引号括起来;decplusblank表示对于十进制数据类型,用空格代替最前面的加号,因为默认情况下会在十进制数据前面加上正负号的。
    例三:以ASC格式将数据导出到文件
    Export命令是不支持ASC格式文件的,所以如果想导出ASC这样规整的格式,需要程序员自己进行转换操作,思路是将各种数据类型都转换成定长字符串,然后把各个要导出的字段合并成为一个字段。
    例如创建如下结构的表n:
    create table n(a int,b date,c time,d varchar(5),e char(4),f double)
    然后插入两条数据:
    insert into n values(15,'2004-10-21','23:12:23','abc','hh',35.2)
    insert into n values(5,'2004-1-21','3:12:23','bc','hhh',35.672)
    要想把这两条数据以规整的格式导出到文件中,进行如下操作:
    export to c:\test.txt of del select char(a) || char(b) || char(c) || char(d,5) || e || char(f) as tmp from n
    这样导出的结果与ASC格式的文件非常类似,只是每一行的前后多出了一对双引号,对此我们可以使用文本工具(如写字板、记事本等)把双引号删除掉,也可以置之不理,在以后导入的时候直接控制格式(忽略双引号)
    在文件中的格式为:
    "15 2004-10-2123.12.23abc hh 3.52E1 "
    "5 2004-01-2103.12.23bc hhh 3.5672E1 "
    例四:大数据的导出
    export to d:\myfile.del of del lobs to d:\lob\ lobfile lobs modified by lobsinfile select * from emp_photo
    该命令把emp_photo表的数据导出到d:\myfile.del文件中,其结果为:
    <pre>
    "000130","bitmap","lobs.001.0.43690/"
    "000130","gif","lobs.001.43690.29540/"
    "000130","xwd","lobs.001.73230.45800/"
    "000140","bitmap","lobs.001.119030.71798/"
    "000140","gif","lobs.001.190828.29143/"
    "000140","xwd","lobs.001.219971.73908/"
    "000150","bitmap","lobs.001.293879.73438/"
    "000150","gif","lobs.001.367317.39795/"
    "000150","xwd","lobs.001.407112.75547/"
    "000190","bitmap","lobs.001.482659.63542/"
    "000190","gif","lobs.001.546201.36088/"
    "000190","xwd","lobs.001.582289.65650/"
    </pre>
    其中第三个字段是BLOB类型,在该文件中只保存了一个标志,相当于一个指针,真正的LOB数据保存在d:\lob目录下的lobs.001、lobs.002、......等一系列文件中。命令中lobs to 后面指定大对象数据保存在什么路径下(注意,该路径必须事先已经存在,否则会报错),lobfile 后面指定大对象数据保存在什么文件中,不要指定扩展名,DB2会根据数据量自动追加.001、.002等扩展名,同时不要忘记加上modified by lobsinfile子句。



    例五:把导出信息保存在消息文件中。
    export to d:\awards.ixf of ixf messages d:\msgs.txt select * from staff where dept = 20

    这个例子把staff表中dept=20的数据导出到d:\awards.ixf文件中,所有的导出信息都保存在d:\msgs.txt文件中(无论是成功、警告还是失败信息),这样,管理员可以通过观察信息文件找到问题所在。
    例六:给导出数据列重命名。
    export to d:\awards.ixf of ixf method n(c1,c2,c3,c4,c5,c6,c7) messages d:\msgs.txt select * from staff where dept=20
    在默认情况下,导出的每一列数据以表中对应的字段名自动命名,我们可以通过method n子句给每一列重新命名,需要注意的是,这个子句只在ixf和wsf格式文件中有效,在文本文件中不能使用。


    数据导入导出基本示例

    db2cmd(D:\IBM_DB2\SQLLIB\BIN目录下)

    db2 connect to oyd user db2 using pwd


    DB2 "Export to c:/db2_/ATAPPLYBORROWLIST.IXF OF IXF select * from ATAPPLYBORROWLIST"

    DB2 "IMPORT FROM c:/db2_/ATAPPLYBORROWLIST.IXF OF IXF CREATE INTO ATAPPLYBORROWLIST"



    DB2常用的命令
    DB2常用的命令
    1.启动数据库
      db2start
    2.停止数据库
      db2stop
    3.连接数据库
      db2 connect to oyd user db2 using pwd

    (注:oyd为数据库名)
    4.读数据库管理程序配置
      db2 get dbm cfg
    5.写数据库管理程序配置
      db2 update dbm cfg using 参数名 参数值
    6.读数据库的配置
      db2 connect to o_yd user db2 using pwd
      db2 get db cfg for o_yd
    7.写数据库的配置
      db2 connect to o_yd user db2 using pwd
      db2 update db cfg for o_yd using 参数名 参数值
    8.关闭所有应用连接
      db2 force application all
      db2 force application ID1,ID2,,,Idn MODE ASYNC
      (db2 list application for db o_yd show detail)
    9.备份数据库
      db2 force application all
      db2 backup db o_yd to d:
      (db2 initialize tape on [url=file://\\.\tape0]\\.\tape0)
      (db2 rewind tape on [url=file://\\.\tape0]\\.\tape0)
      db2 backup db o_yd to [url=file://\\.\tape0]\\.\tape0
    10.恢复数据库
      db2 restore db o_yd from d: to d:
      db2 restore db o_yd from [url=file://\\.\tape0]\\.\tape0 to d:
    11.绑定存储过程
    db2 connect to o_yd user db2 using pwd
    db2 bind c:\dfplus.bnd
    拷贝存储过程到服务器上的C:\sqllib\function目录中
    12.整理表
      db2 connect to o_yd user db2 using pwd
      db2 reorg table ydd
      db2 runstats on table ydd with distribution and indexes all

    13.导出表数据
      db2 export to c:\dftz.txt of del select * from dftz
      db2 export to c:\dftz.ixf of ixf select * from dftz
    14.导入表数据
    import from c:\123.txt of del insert into ylbx.czyxx
    db2 import to c:\dftz.txt of del commitcount 5000 messages c:\dftz.msg insert into dftz
    db2 import to c:\dftz.ixf of ixf commitcount 5000 messages c:\dftz.msg insert into dftz
    db2 import to c:\dftz.ixf of ixf commitcount 5000 insert into dftz
    db2 import to c:\dftz.ixf of ixf commitcount 5000 insert_update into dftz
    db2 import to c:\dftz.ixf of ixf commitcount 5000 replace into dftz
    db2 import to c:\dftz.ixf of ixf commitcount 5000 create into dftz   (仅IXF)
    db2 import to c:\dftz.ixf of ixf commitcount 5000 replace_create into dftz (仅IXF)

    15.执行一个批处理文件
        db2 –tf 批处理文件名
      (文件中每一条命令用 ;结束)
    16.自动生成批处理文件
      建文本文件:temp.sql
    select 'runstats on table DB2.' || tabname || ' with distribution and detailed indexes all;' from syscat.tables where tabschema='DB2' and type='T';
    db2 –tf temp.sql>runstats.sql
    17.自动生成建表(视图)语句
    在服务器上:C:\sqllib\misc目录中
    db2 connect to o_yd user db2 using pwd
    db2look –d o_yd –u db2 –e –p –c c:\o_yd.txt
    18.其他命令
    grant dbadm on database to user bb

    19select * from czyxx fetch first 1 rows only
    20db2look –d ylbx –u db2admin –w –asd –a –e –o a.txt21. 显示当前用户所有表

      list tables
    22.列出所有的系统表

      list tables for system
    23.查看表结构
      db2 describe select * from user.tables





    DB2常用的SQL语句及字符串等函数

    1、组合语句执行

    BEGIN   ATOMIC

    表达式1 分号 空格/回车

    表达式2 分号 空格/回车

    END

    2、应该限制访问权限的表(应该撤销这些表PUBLIC SELECT访问权)

    SYSCAT.DBAUTH

    SYSCAT.TABAUTH

    SYSCAT.PACKAGEAUTH

    SYSCAT.INDEXAUTH

    SYSCAT.COLAUTH

    SYSCAT.PASSTHRUAUTH

    SYSCAT.SCHEMAAUTH



    比较有用的目录表

    SYSCAT.COLUMNS:包含每一行对应于表或视图中定义的列

    SYSCAT.INDEXCOLUSE:包含每一行包含的所有列

    SYSCAT.INDEXES:包含每一行对应于表或视图中定义的每个索引

    SYSCAT.TABLES:所创建每个表,视图,别名对应其中一行

    SYSCAT.VIEWS:所创建每个视图对应其中一行或几行



    通过索引保持数据唯一性:CREATE UNIQUE INDEX INDEXNAME ON TABLE (COLUMN)

    消除重复行:SELECT DISTINCT COLUMN FROM TABLE



    3、DB2关于时间的一些函数

    得到当前时间的年份、月份、天、小时等等:

    YEAR (current timestamp)
    MONTH (current timestamp)
    DAY (current timestamp)
    HOUR (current timestamp)
    MINUTE (current timestamp)
    SECOND (current timestamp)
    MICROSECOND (current timestamp)

    分别得到当时的日期和时间

    DATE (current timestamp)
    TIME (current timestamp)

    关于时间的一些计算:

    current date + 1 YEAR
    current date + 3 YEARS + 2 MONTHS + 15 DAYS
    current time + 5 HOURS - 3 MINUTES + 10 SECONDS

    计算两个日期之间有多少天:

    days (current date) - days (date(’1999-10-22′))

    得到去除毫秒的当前时间:

    CURRENT TIMESTAMP - MICROSECOND (current timestamp) MICROSECONDS

    将时间转换成字符串:

    char(current date)
    char(current time)
    char(current date + 12 hours)

    将字符串转换成时间:

    TIMESTAMP (’2002-10-20-12.00.00.000000′)
    TIMESTAMP (’2002-10-20 12:00:00′)
    DATE (’2002-10-20′)
    DATE (’10/20/2002′)
    TIME (’12:00:00′)
    TIME (’12.00.00′)



    注意:在DB2的命令编辑器中可以输入SQL语句和DB2中的内部命令。要想显示当前时间的话,不能直接输入current time,这个只能在SQL语言中引用,要想显示有下面方式:

    1) VALUES (current time)

    2) SELECT CURRENT TIME FROM SYSIBM.SYSDUMMY1

    这个与SQL SERVER2000中不一样,在SQL SERVER2000中可以输入Getdate()得到时间,既可以显示,也可以在语句SQL中用。



    4、所有返回前N条数据的表达式

    在SQL SERVER2000中使用TOP N 格式

    比如: SELECT TOP 10 CARDNO FROM CARD

    在DB2中使用fetch first N rows only 格式

    比如:SELECT CARDNO FROM SEALCARD fetch first 10 rows only



    5、函数使用

    查看系统函数: SELECT * FROM SYSibm.sysfunctions;

    比如:ABS(-89)可以作为值输入到SQL中,但是要想在命令编辑器中显示函数的结果的话可以用下列方式:

    1)SELECT ABS(-89) FROM SYSIBM.SYSDUMMY1;

    2)VALUES ABS(-89);



    6、存储过程

    在进行DB2存储过程开发时,我们可以利用很多DB2自带的工具,例如开发中心,控制中心等。但有时使用脚本能带给开发人员更大的灵活性和更高的工作效率。

    在开始开发一个新的或修改一个已存在的存储过程时,我们通常会进行下面一些准备工作:

    1.       查看该存储过程会用到的表的表结构、字段类型、相关索引和示例数据。

    2.       查看相关的存储过程或用户自定义函数(UDF)的定义。

    3.       查找无效的存储过程并生成绑定语句。

    4.       如某个表发生了改变,查看依赖于该表的所有视图、存储过程和用户自定义函数(UDF)

    虽然上述信息都可以通过DB2提供的开发工具和管理工具获得,但是通过脚本可以更快速的获得所需信息,并且可以重复执行。

    使用脚本完成上述任务的关键是理解和使用DB2的系统表。我们先简单回顾一下有关的DB2的系统表和视图:

    1.       syscat.routines:存储所有的存储过程和用户自定义函数(UDF)信息。其中routinename字段为存储过程或用户自定义函数(UDF)的名称,routinetype字段表示该记录表示的是存储过程(P)还是用户自定义函数(F),lib_id字段为存储过程编译后生成的包序列号,origin字段表示该存储过程或用户自定义函数的出处(Q表示是由SQL组成的,E表示用户定义的且是外部的),valid字段表示该存储过程或用户自定义函数是否有效,如果origin字段不是Q的话,该域为空。

    2.       syscat.packages:存储所有被绑定的程序包。其中pkgname表示包名称,valid字段表示该包是否合法。

    3.       syscat.packagedep:存储关于程序包的依赖关系。其中pkgname字段表示程序包名,btype字段表示被依赖对象的类型,bname字段表示被依赖对象的名称。

    4.       syscat.routinedep:存储关于程序(routine)的依赖关系。其中routinename字段表示程序名,btype字段表示被依赖对象的类型,bname字段表示被依赖对象的名称。

    5.       syscat.viewdep:存储了关于视图的依赖关系。其中viewname字段表示视图名,btype字段表示被依赖对象的类型,bname字段表示被依赖对象的名称。

    回顾并了解了上述系统表和视图,我们就可以很容易的创建脚本以完成前面提到的开发存储过程所要做的准备工作。

    1. 查看该表结构、字段类型、相关索引和示例数据

    虽然我们可以查询sysibm.systables表获得表结构,但有一种更简便的方法来获取表结构,即使用db2look工具。该工具可以生成创建该表和相关的索引的DDL。如我们要获取指定数据库中指定表的结构和前20条数据作为参考,可编写脚本viewtbl.cmd如下,传入参数分别为数据库名和表名。

    @echo ------------------ DDL of table %2 and related index(ex) ------------------

    @db2look -d %1 -t %2 -e

    @echo ------------------ fisrt 20 rows in table %2 ------------------

    @db2 select * from %2 fetch first 20 rows only


    2.查看已存在的存储过程和用户自定义函数(UDF)的定义,将结果存入文件并自动打开结果文件。

    可以从syscat.routines表中做简单查询实现脚本viewrtn.cmd。

    @db2 SELECT text FROM SYSCAT.ROUTINES WHERE ROUTINENAME=upper('%1') > %1.sql

    @start %1.sql


    3.查看所有无效的存储过程并生成绑定语句

    删除存储过程引用的表会引起该存储过程无效。无效存储过程可以采用查询syscat.routines和syscat.packages的方法获得:

    SELECT

      RTRIM(r.routineschema) || '.' || RTRIM(r.routinename) AS spname ,

      RTRIM(r.routineschema) || '.' || 'P'||SUBSTR(CHAR(r.lib_id+10000000),2) AS pkgname

    FROM

      SYSCAT.routines r

    WHERE

      r.routinetype = 'P'

      AND (

        (r.origin = 'Q' AND r.valid != 'Y')

        OR EXISTS (

            SELECT 1 FROM syscat.packages

            WHERE pkgschema = r.routineschema

            AND pkgname = 'P'||SUBSTR(CHAR(r.lib_id+10000000),2)

            AND valid !='Y'

        )

      )

    ORDER BY spname


    注意要同时查询syscat.routines和syscat.packages表,因为在程序包无效时syscat.routines中的valid值仍可能为Y。

    如果要自动生成重新绑定语句,只需将上述SQL改写并存成invalidSP.cmd:

    @echo off

    db2 "SELECT [url=mailto:]'@db2 rebind package '|| RTRIM(r.routineschema) || '.' || 'P'||SUBSTR(CHAR(r.lib_id+10000000),2)||' resolve any' FROM SYSCAT.routines r WHERE r.routinetype = 'P' AND ((r.origin = 'Q' AND r.valid != 'Y') OR EXISTS (SELECT 1 FROM syscat.packages WHERE pkgschema = r.routineschema AND pkgname = 'P'||SUBSTR(CHAR(r.lib_id+10000000),2) AND valid !='Y') )" >rebindsp.bat


    4.查看某个表所依赖的视图、存储过程和用户自定义函数(UDF)

    使用上述系统视图,我们很容易编写出脚本:

    @echo off

    echo --- dependent SPs ---

    db2 "select proc.procschema, proc.procname from syscat.routines r, syscat.procedures proc, syscat.packagedep pdep where pdep.bname=upper('%2') and pdep.bschema=upper('%1') and r.specificname=proc.specificname AND pdep.pkgname = 'P'||SUBSTR(CHAR(r.lib_id+10000000),2)"



    echo --- dependent UDF ---

    db2 select routineschema, routinename from syscat.routinedep where bschema = upper('%1') and bname = upper('%2') and btype ='T' order by bname



    echo --- dependent view ---

    db2 select viewschema, viewname from syscat.viewdep where bschema = upper('%1') and bname = upper('%2') and btype ='T' order by bname


    行业借鉴经验:提高DB2存储过程性能和健壮性的3个最佳实践

    最佳实践1:在创建存储过程语句中提供必要的参数

    创建存储过程语句(CREATE PROCEDURE)可以包含很多参数,虽然从语法角度讲它们不是必须的,但是在创建存储过程时提供这些参数可以提高执行效率。下面是一些常用的参数:

    l       容许SQL(allowed-SQL)

    容许SQL(allowed-SQL)子句的值指定了存储过程是否会使用SQL语句,如果使用,其类型如何。它的可能值如下所示:

    NO SQL: 表示存储过程不能够执行任何SQL语句。

    CONTAINS SQL: 表示存储过程可以执行SQL语句,但不会读取SQL数据,也不会修改SQL数据。

    READS SQL DATA: 表示在存储过程中包含不会修改SQL数据的SQL语句。也就是说该储存过程只从数据库中读取数据。

    MODIFIES SQL DATA: 表示存储过程可以执行任何SQL语句。即可以对数据库中的数据进行增加、删除和修改。

    如果没有明确声明allowed-SQL,其默认值是MODIFIES SQL DATA。不同类型的存储过程执行的效率是不同的,其中NO SQL效率最好,MODIFIES SQL DATA最差。如果存储过程只是读取数据,但是因为没有声明allowed-SQL类型,它会被当作对数据进行修改的存储过程来执行,这显然会降低程序的执行效率。因此创建存储过程时,应当明确声明其allowed-SQL类型。

    l       返回结果集个数(DYNAMIC RESULT SETS n)

    存储过程能够返回0个或者多个结果集。为了从存储过程中返回结果集,需要执行如下步骤:

    在CREATE PROCEDURE 语句的DYNAMIC RESULT SETS子句中声明存储过程将要返回的结果集的数量。如果这里声明的返回结果集的数量小于存储过程中实际返回的结果集数量,在执行该存储过程的时候,DB2会返回一个警告。

    使用WITH RETURN子句,在存储过程体中声明游标。

    为结果集打开游标。当存储过程返回的时候,保持游标打开。

    在创建存储过程时指定返回结果集的个数可以帮助程序员验证存储过程是否返回了所期待数量的结果集,提高了程序的完整性。

    最佳实践2:对输入参数进行必要的的检查和预处理

    无论使用哪种编程语言,对输入参数的判断都是必须的。正确的参数验证是保证程序良好运行的前提。同样的,在DB2存储过程中对输入参数的验证和处理也是很重要的。正确的验证和预处理操作包括:

    如果输入参数错误,存储过程应返回一个明确的值告诉客户应用,然后客户应用可以根据返回的值进行处理,或者向存储过程提交新的参数,或者去调用其他的程序。

    根据业务逻辑,对输入参数作一定的预处理,如大小写的转换,NULL与空字符串或0的转换等。

    在DB2储存过程开发中,如需要遇到对空(NULL)进行初始化,我们可以使用COALESCE函数。该函数返回第一个非NULL的参数。例如,COALESCE(piName,''),如果变量piName为NULL,那么函数会返回'',否则就会返回piName本身的值。因此,可以用下面的代码检查piName是否非NULL并且非空字符串:

    SET poGenStatus = 0;                                  

      SET piName   =RTRIM(COALESCE(piName, ''));

      IF (piName ='')  

      THEN                    

        SET poGenStatus = 34100;    

        RETURN poGenStatus;      

      ENDIF;    


    同理,使用COALESCE可以对任何类型的输入参数进行初始化或验证。下面是对参数初始化规则的一个总结:

    1.     输入参数为字符类型,且允许为NULL的,如希望缺省值为空字符串,可以使用COALESCE(inputParameter, '')把NULL转换成空字符串;

    2.     输入类型为整型,且允许为NULL的,如希望缺省值为0,可以使用COALESCE(inputParameter,0),把NULL转换成0;

    3.     输入参数为字符类型,且不允许是NULL或空字符串的,可以使用RTRIM(COALESCE(inputParameter, ''))把NULL转换成空字符串,然后验证函数返回值是否为空字符串;

    4.     输入类型为整型,且不允许是NULL的,不需要使用COALESCE函数,直接使用IS NULL进行验证。

    最佳实践3:异常(condition)处理

    在存储过程执行的过程中,经常因为数据或者其他问题产生异常(condition)。根据业务逻辑,存储过程应该对异常进行相应处理或直接返回给调用者。此处暂且将condition译为异常以方便理解。实际上有些异常(condition)并非是由于错误引起的。

    当存储过程中的语句返回的SQLSTATE值超过00000的时候,就表明在存储过程中产生了一个异常(condition),它表示出现了错误、数据没有找到或者出现了警告。为了处理存储过程中出现的异常,我们必须在存储过程体中声明异常处理器(condition handler),它可以决定存储过程怎样响应一个或者多个系统定义的异常或者自定义异常。

    异常处理器类型(handler-type)有以下几种:

    l       CONTINUE: 在处理器操作完成之后,会继续执行产生这个异常语句之后的下一条语句。

    l       EXIT: 在处理器操作完成之后,存储过程会终止,并将控制返回给调用者。

    l       UNDO: 在处理器操作执行之前,DB2会回滚存储过程中执行过的SQL操作。在处理器操作完成之后,存储过程会终止,并将控制返回给调用者。

    异常处理器可以处理基于特定SQLSTATE值的自定义异常,或者处理系统预定义异常。系统预定义的3种异常如下所示:

    l       NOT FOUND: 标识导致SQLCODE值为+100或者SQLSATE值为02000的异常。这个异常通常在SELECT没有返回行的时候出现。

    l       SQLEXCEPTIOIN: 标识导致SQLCODE值为负的异常。

    l       SQLWARNING: 标识导致警告异常或者导致正100以上的SQLCODE值的异常。

    如果产生了NOT FOUND 或者SQLWARNING异常,并且没有为这个异常定义异常处理器,系统就会忽略这个异常,并且将控制流转向下一个语句。如果产生了SQLEXCEPTION异常,并且没有为这个异常定义异常处理器,那么存储过程就会失败,系统会将控制流返回调用者。因此如果开发人员想改变这种异常处理流程,必须自定义异常处理器。例如,希望在出现SQLWARNING异常时也终止存储过程,并将名为stmt的变量设为“ABORTED”,可以定义下面语句定义异常处理器:

    DECLAREEXIT HANDLER FOR SQLEXCEPTION, SQLWARNING

        SET stmt ='ABORTED';


    如果预定义异常集仍不能满足需求,可以为特定的SQLSTATE值声明自定义异常,然后再为这个异常定制异常声明处理器。为特定的SQLSTATE值声明自定义异常的语法如下:

    DECLARE condition-name CONDITION FOR SQLSATE ‘mysqlstate’


    定义了异常和异常处理器后,在存储过程执行的任何都使用SIGNAL condition-name语句触发这种自定义类型的异常。

    异常处理器可以由单独的存储过程语句定义,也可以使用复合语句定义。注意在执行复合语句的时候,SQLSATE和SQLCODE的值会被改变,如果需要保留异常前的SQLSATE和SQLCODE值,就需要在复合语句中的第一个语句把SQLSATE和SQLCODE赋予本地变量或参数。下面是一个例子:

      DECLARECONTINUE HANDLER FOR SQLEXCEPTION, SQLWARNING, NOTFOUND

      BEGINNOT ATOMIC            

        -- Capture SQLCODE & SQLSTATE to local variables

        SELECT SQLCODE, SQLSTATE    

        INTO   hSqlcode, hSqlstate  

        FROM   SYSIBM.SYSDUMMY1;    

        -- your handler statements below

        ……

      END;


    应用难点技巧:使用Case让你的SQL语句有条件的执行

    我们在编写SQL语句时,常常遇到希望SQL能够按条件执行的情况。这里的条件不是指Where子句中的条件,而是指让DB2根据条件执行SQL的语句块。大多数情况下我们可以使用case来实现。

    例如,我们希望从员工表中查出员工的工资情况,如果小于20000,则标志为low,20000到50000间为middle,否则为high。一般大家会想到先取出工资数据然后在Java代码中做判断,但我们也可以在SQL中完成上述操作。如下例:

    select empno, sex, salary,

    case

    when salary < 20000 then 'low'

    when salary >=20000 and salary <50000 then 'middle'

    else 'high'

    end as salaryclass

    from employee


    类似的,如果想在SQL语句中把性别翻译成文字,也可以用case实现,注意这两条SQL语句使用了不同的case表达式写法:

    select empno,

    case sex

    when 'M' then 'male'

    when 'F' then 'female'

    else 'invalid'

    end,

    salary

    from employee


    Case不但能够在Select子句中使用,在From子句和Where子句中同样可以使用。下面是在Where子句中使用的一个例子:

    select empno, sex, age

    from employee

    where

    case sex

    when 'M' then 55

    when 'F' then 50

    end > age


    在From子句中使用的例子极为少见,下面是一个极端的例子。在合同表ctrct_list、客户表customer和订单表quote中都有合同号字段,但订单表中的合同号可能为空。要求查询出订单表订单id和合同号,如订单表中合同号为空的话,查出客户表中相应的合同号。

    select distinct

      q.quote_id,

      case rtrim(coalesce(q.ctrct_num, ''))

        when '' then rtrim(coalesce(c.ctrct_num, ''))

        else rtrim(coalesce(q.ctrct_num, ''))

      end ctrct_num

    from

      (quote q

      left outer join customer c

        on q.sold_to_cust_num = c.cust_num)

      inner join ctrct_list cl

        on cl.cust_num = q.sold_to_cust_num

        and cl.ctrct_num = (

              case rtrim(coalesce(q.ctrct_num, ''))

              when '' then c.ctrct_num

              else q.ctrct_num

              end

            )


    有时让SQL语句有条件的执行也可以不使用case。下面是一个例子:

    select *

    from EMPLOYEE

    WHERE

    ((job='MANAGER') AND vMgrFlag=1)

    or

    ((job='DESIGNER' or job='ANALYST') AND vTechFlag =1)

    or

    ((job='CLERK' or job='OPERATOR') AND vOfficeFlag=1)


    此SQL可以要求根据标志位的不同选择出不同类型的雇员。各个标志位在执行SQL前应提前设置好。这种方法可以在某些情况下将动态SQL改写为静态SQL,因此在编写存储过程时非常实用。但要指出的是,DB2的查询优化器不可能将这种SQL也优化得非常高效,因此在数据量比较大时可能会带来性能问题。开发人员需要在编写完成后使用实际数据测试,必要的话进行性能优化。





































    IBM DB2 数据库几个应用上的小技巧

    1. 查看本地节点目录

    命令窗口中输入:db2 list node directory

    2. 编目一个TCP/IP节点

    命令窗口:db2 catalog tcpip node remote server ostype

    3. 取消节点编目

    db2 uncatalog node

    4. 查看系统数据库目录

    db2 list database directory

    5. 查看本地数据库目录

    db2 list database directory on <盘符>

    在本地数据库目录中有而系统数据库目录中没有的数据库不能访问,可以在控制中心中选中<数据库>右键单击选择添加,然后输入需要添加的数据库名称或者点击刷新按钮选择数据库,加入数据库后即可以访问。

    6. 编目数据库

    db2 catalog database as at node

    7. 取消数据库编目

    db2 uncatalog database

    8. 测试远程数据库的连接

    db2 connect to user using

    9. 任何用户均可通过设置Current Schema专用寄存器为特定的数据库连接设置默认模式,初始默认值为当前会话用户的权限ID。

    set schema =

    可以由用户交互式的使用,也可在应用程序中使用,如果用Dynamicrules Bind选项绑定包,这个语句就没有作用。此语句不在事务控制之下。

    10. 代码页的设置

    在创建数据库时设置字符集

    create database using codeset territory

    例:

    create database dbtest using codeset IBM-437 territory US

    也可以设置整个数据库的代码页,在win2000/NT/xp中,在我的电脑-->属性-->高级-->环境变量中添加变量DB2CODEPAGE = ,例:DB2CODEPAGE = 437 或 DB2CODEPAGE = 1386。或者在IBM DB2命令窗口输入 db2set DB2CODEPAGE=1386,设置后需要重新启动DB2生效。

    11. DB2低版本数据到高版本的迁移

    先将低版本数据备份使用恢复功能导入高版本数据库,然后在命令窗口输入 db2 migrate database 。

    12. 表名或模式中含有引号时访问表

    命令窗口:db2 select * from "tabschema"."tabname"

    命令行处理器:db2=> select * from "tabschema"."tabname"

    13. 导出数据库的表结构生成DDL文件

    命令窗口:db2look -d -e -c -o

    14. 执行脚本文件

    命令窗口:db2 -tvf

    15. 代码页的转换

    16. 获取当前DB2的版本

    select * from sysibm.sysversions

    17. DB2表的字段的修改限制?

    只能修改VARCHAR2类型的并且只能增加不能减少

    alter table alter column set data type varchar(SIZE)

    18. 如何查看表的结构?

    describe table

    or

    describe select * from .

    19. 如何快速清除一个大表?

    ALTER TABLE TABLE_NAME ACTIVE NOT LOGGED INITALLY WITH EMPTY TABLE

    20. 如何查看数据库的存储过程?

    SELECT * FROM SYSCAT.PROCEDURES

    21. 如何查看表的约束?

    SELECT * FROM SYSCAT.CHECKS WHERE TABNAME =

    22. 如何查看表的引用完整约束?

    SELECT * FROM SYSCAT.REFERENCES WHERE TABNAME =

    23. 如何知道BUFFERPOOLS状况?

    select * from SYSCAT.BUFFERPOOLS

    24. 如何在命令行下查看修改实例和数据库配置参数?

    查看实例配置参数: db2 get dbm cfg

    修改实例配置参数: db2 update dbm cfg using 参数名 新值

    查看数据库配置参数: db2 get db cfg for

    修改数据库配置参数: db2 update db cfg for using 参数名 新值

    25. 如何修改缓冲区?

    增加缓冲区: create bufferpool size [pagesize 4096] {[not] EXTENDED STORAGE}

    修改缓冲区: alter bufferpool size {[not] EXTENDED STORAGE}

    删除缓冲区: drop bufferpool

    如果缓冲区大小设置为 -1 表示缓冲池的页面数目由数据库配置参数buffpage决定。

    注意: 数据库配置参数buffpage仅对缓冲区大小设置为 -1 的缓冲池起作用。

    26. 多个字段时如何不通过使用select子句使用in/not in

    select * from tabschema.tabname where (colA, colB, colC) [not] in (values (valueA1, valueB1, valueC1), (valueA2, valueB2, valueC2), ...(valueAn, valueBn, valueCn))

    27. 查看当前连接到数据库的应用

    db2 list application [show detail]

    28. 如何确认DB2数据库的一致性

    db2dart /DB

    /DB表示检查整个数据库的一致性

    29. 测试SQL语句的性能

    db2batch -d -f [-a userid/passwd] [-r ]

    -r 选项表示将查询结果输出到一个文件中。

    30. 导出某个表的数据

    export to

    如:导出用户表

    export to c:user.ixf of ixf select * from user

    31. 导入数据

    import from

    如:导入用户表。导入时可以直接建立新表。如果有该表存在也可以用INSERT 插入,或者用UPDATE更新

    import from c:user.ixf of ixf [Create/Insert into / update] tablename



    32.如何知道一个用户有多少表?
     SELECT * FROM SYSIBM.SYSTABLES WHERE CREATOR='USER'
    33.如何知道用户下的函数?
    select * from IWH.USERFUNCTION
    select * from sysibm.SYSFUNCTIONS 
    34.如何知道用户下的VIEW数?
    select * from sysibm.sysviews WHERE CREATOR='USER'  
    35.如何知道当前DB2的版本?
    select * from sysibm.sysvERSIONS
    36.如何知道用户下的TRIGGER数?
    select * from sysibm.SYSTRIGGERS WHERE SCHEMA='USER'
    37.如何知道TABLESPACE的状况?
    select * from sysibm.SYSTABLESPACES
    38.如何知道SEQUENCE的状况?
    select * from sysibm.SYSSEQUENCES
    39.如何知道SCHEMA的状况?
    select * from sysibm.SYSSCHEMATA
    40.如何知道INDEX的状况?
    select * from sysibm.SYSINDEXES
    41.如何知道表的字段的状况?
    select * from sysibm.SYSCOLUMNS WHERE TBNAME='AAAA'
    42.如何知道DB2的数据类型?
    select * from sysibm.SYSDATATYPES
    43.如何知道BUFFERPOOLS状况?
    select * from sysibm.SYSBUFFERPOOLS
    44.如何查看数据库的包?
    select * fromsys CAT.PACKAGES
    45.如何查看数据库的存储过程?
    SELECT * FROM SYSCAT.PROCEDURES

    或者 SELECT * FROM SYSibm.sysprocedures
    46.如何查看表的约束?
    SELECT * FROM SYSCAT.CHECKS WHERE TABNAME='AAAA'
    47.如何查看表的引用完整约束?
    SELECT * FROM SYSCAT.REFERENCES WHERE TABNAME='AAAA'





    DB2应用经验

    //建立数据库DB2_GCB
    CREATE DATABASE DB2_GCB ON G: ALIAS DB2_GCB
    USING CODESET GBK TERRITORY CN COLLATE USING SYSTEM DFT_EXTENT_SZ 32
    //连接数据库
    connect to sample1 user db2admin using 8301206
    //建立别名
    create alias db2admin.tables for sysstat.tables;
    CREATE ALIAS DB2ADMIN.VIEWS FOR SYSCAT.VIEWS
    create alias db2admin.columns for syscat.columns;
    create alias guest.columns for syscat.columns;
    //建立表
    create table zjt_tables as
    (select * from tables) definition only;
    create table zjt_views as
    (select * from views) definition only;
    //插入记录
    insert into zjt_tables select * from tables;
    insert into zjt_views select * from views;

    //建立视图
    create view V_zjt_tables as select tabschema,tabname from zjt_tables;


    //建立触发器
    CREATE TRIGGER zjt_tables_del
    AFTER DELETE ON zjt_tables
    REFERENCING OLD AS O
    FOR EACH ROW MODE DB2SQL
    Insert into zjt_tables1 values(substr(o.tabschema,1,8),substr(o.tabname,1,10))


    //建立唯一性索引
    CREATE UNIQUE INDEX I_ztables_tabname
    ON zjt_tables(tabname);


    //查看表
    select tabname from tables
    where tabname='ZJT_TABLES';

    //查看列
    select SUBSTR(COLNAME,1,20) as 列名,TYPENAME as 类型,LENGTH as 长度
    from columns
    where tabname='ZJT_TABLES';

    //查看表结构
    db2 describe table user1.department
    db2 describe select * from user.tables


    //查看表的索引
    db2 describe indexes for table user1.department

    //查看视图
    select viewname from views
    where viewname='V_ZJT_TABLES';

    //查看索引
    select indname from indexes
    where indname='I_ZTABLES_TABNAME';

    //查看存贮过程
    SELECT SUBSTR(PROCSCHEMA,1,15),SUBSTR(PROCNAME,1,15)
    FROM SYSCAT.PROCEDURES;

    //类型转换(cast)
    ip datatype:varchar
    select cast(ip as integer)+50 from log_comm_failed

    //重新连接
    connect reset

    //中断数据库连接
    disconnect db2_gcb


    //view application
    LIST APPLICATION;

    //kill application

    FORCE APPLICATION(0);

    db2 force applications all (强迫所有应用程序从数据库断开)

    //lock table

    //独占
    lock table test in exclusive mode

    //共享

    lock table test in share mode

    //显示当前用户所有表
    list tables

    //列出所有的系统表
    list tables for system

    //显示当前活动数据库
    list active databases

    //查看命令选项
    list command options

    //系统数据库目录
    LIST DATABASE DIRECTORY

    //表空间
    list tablespaces

    //表空间容器
    LIST TABLESPACE CONTAINERS FOR
    Example: LIST TABLESPACE CONTAINERS FOR 1


    //显示用户数据库的存取权限
    GET AUTHORIZATIONS

    //启动实例
    DB2START

    //停止实例
    db2stop

    //表或视图特权
    grant select,delete,insert,update on tables to user
    grant all on tables to user WITH GRANT OPTION

    //程序包特权
    GRANT EXECUTE
    ON PACKAGE PACKAGE-name
    TO PUBLIC

    //模式特权
    GRANT CREATEIN ON SCHEMA SCHEMA-name TO USER

    //数据库特权
    grant connect,createtab,dbadm on database to user

    //索引特权
    grant control on index index-name to user

    //信息帮助 (? XXXnnnnn )
    例:? SQL30081

    //SQL 帮助(说明 SQL 语句的语法)

    help statement

    例如,help SELECT

    SQLSTATE 帮助(说明 SQL 的状态和类别代码)

    ? sqlstate 或 ? class-code

    //更改与“管理服务器”相关的口令

    db2admin setid username password

    //创建 SAMPLE 数据库

    db2sampl

    db2sampl F:(指定安装盘)

    //使用操作系统命令

    ! dir

    //转换数据类型 (cast)

    SELECT EMPNO, CAST(RESUME AS VARCHAR(370))

    FROM EMP_RESUME

    WHERE RESUME_FORMAT = 'ascii'

    //要运行 DB2 Java 存储过程或 UDF,还需要更新服务器上的 DB2 数据库管理程序配置,以包括在该机器上安装 JDK 的路径

    db2 update dbm cfg using JDK11_PATH d:\sqllib\java\jdk

    TERMINATE

    update dbm cfg using SPM_NAME sample

    //检查 DB2 数据库管理程序配置

    db2 get dbm cfg

    //检索具有特权的所有授权名

    SELECT DISTINCT GRANTEE, GRANTEETYPE, 'DATABASE' FROM SYSCAT.DBAUTH

    UNION

    SELECT DISTINCT GRANTEE, GRANTEETYPE, 'TABLE ' FROM SYSCAT.TABAUTH

    UNION

    SELECT DISTINCT GRANTEE, GRANTEETYPE, 'PACKAGE ' FROM SYSCAT.PACKAGEAUTH

    UNION

    SELECT DISTINCT GRANTEE, GRANTEETYPE, 'INDEX ' FROM SYSCAT.INDEXAUTH

    UNION

    SELECT DISTINCT GRANTEE, GRANTEETYPE, 'COLUMN ' FROM SYSCAT.COLAUTH

    UNION

    SELECT DISTINCT GRANTEE, GRANTEETYPE, 'SCHEMA ' FROM SYSCAT.SCHEMAAUTH

    UNION

    SELECT DISTINCT GRANTEE, GRANTEETYPE, 'SERVER ' FROM SYSCAT.PASSTHRUAUTH

    ORDER BY GRANTEE, GRANTEETYPE, 3

    create table yhdab

    (id varchar(10),

    password varchar(10),

    ywlx varchar(10),

    kh varchar(10));

    create table ywlbb

    (ywlbbh varchar(8),

    ywmc varchar(60))

    //修改表结构

    alter table yhdab ALTER kh SET DATA TYPE varchar(13);

    alter table yhdab ALTER ID SET DATA TYPE varchar(13);

    alter table lst_bsi alter bsi_money set data type int;

    insert into yhdab values

    ('20000300001','123456','user01','20000300001'),

    ('20000300002','123456','user02','20000300002');

    //业务类型说明

    insert into ywlbb values

    ('user01','业务申请'),

    ('user02','业务撤消'),

    ('user03','费用查询'),

    ('user04','费用自缴'),

    ('user05','费用预存'),

    ('user06','密码修改'),

    ('user07','发票打印'),

    ('gl01','改用户基本信息'),

    ('gl02','更改支付信息'),

    ('gl03','日统计功能'),

    ('gl04','冲帐功能'),

    ('gl05','对帐功能'),

    ('gl06','计费功能'),

    ('gl07','综合统计')

    说明 目录视图

    检查约束 SYSCAT.CHECKS

    列 SYSCAT.COLUMNS

    检查约束引用的列 SYSCAT.COLCHECKS

    关键字中使用的列 SYSCAT.KEYCOLUSE

    数据类型 SYSCAT.DATATYPES

    函数参数或函数结果 SYSCAT.FUNCPARMS

    参考约束 SYSCAT.REFERENCES

    模式 SYSCAT.SCHEMATA

    表约束 SYSCAT.TABCONST

    表 SYSCAT.TABLES

    触发器 SYSCAT.TRIGGERS

    用户定义函数 SYSCAT.FUNCTIONS

    视图 SYSCAT.VIEWS

    二进制大对象 (BLOB) 字符串。

    字符大对象 (CLOB) 字符串,它的字符序列可以是单字节字符或多字节字符,或这两者的组合。

    双字节字符大对象 (DBCLOB) 字符串,它的字符序列是双字节字符。

    第一种规范形式

    表中的每一行和每一列均有一个值,永远不会是一组值。

    第二种规范形式

    不在关键字中的每一列提供取决于整个关键字的事实。

    第三种规范形式

    每个非关键字列提供与其他非关键字列无关并只取决于该关键字的事实。

    第四种规范形式

    没有行包含有关一个实体的两个或更多个独立的多值事实。

    数据类型 类型 特性 示例或范围

    CHAR(15) 定长字符串 最大长度为 254 'Sunny day '

    VARCHAR(15) 变长字符 最大长度为 4000 'Sunny day'

    SMALLINT 数字 长度为 2 字节精度为 5 位 范围为-32768 至 32767

    INTEGER 数字 长度为 4 字节精度为 10 位 范围为-2147483648 至 2147483647

    REAL 数字 单精度浮点32 位近似值 范围为 -3.402E+38 至-1.175E-37或 1.175E-37 至-3.402E+38或零

    DOUBLE 数字 双精度浮点64 位近似值 范围为-1.79769E+308 至-2.225E-307或 2.225E-307 至 1.79769E+308

    或零

    DECIMAL(5,2) 数字 精度为 5小数位为 2 范围为 -10**31+1 至 10**31-1

    DATE 日期时间 三部分值 1991-10-27

    TIME 日期时间 三部分值 13.30.05

    TIMESTAMP 日期时间 七部分值 1991-10-27-13.30.05.000000

    列函数

    列函数对列中的一组值进行运算以得到单个结果值。下列就是一些列函数的示例。

    AVG
    返回某一组中的值除




    SQL Server与Oracle、DB2的性能比较
    开放性   SQL Server
      只能在Windows 上运行,没有丝毫的开放性,操作系统的系统的稳定对数据库是十分重要的。Windows9X系列产品是偏重于桌面应用,NT server只适合中小型企业。而且Windows平台的可靠性,安全性和伸缩性是非常有限的。它不象Unix那样久经考验,尤其是在处理大数据量的关键业务时。
      Oracle
      能在所有主流平台上运行(包括 Windows)。完全支持所有的工业标准。采用完全开放策略。可以使客户选择最适合的解决方案。对开发商全力支持。
      DB2
      能在所有主流平台上运行(包括Windows)。最适于海量数据。DB2在企业级的应用最为广泛,在全球的500家最大的企业中,几乎85%以上用DB2数据库服务器,而国内到97年约占5%。
      可伸缩性,并行性   SQL Server
      并行实施和共存模型并不成熟。很难处理日益增多的用户数和数据卷。伸缩性有限。Oracle
    平行服务器通过使一组结点共享同一簇中的工作来扩展Window NT的能力,提供高可用性和高伸缩性的簇的解决方案。如果WindowsNT不能满足需要, 用户可以把数据库移到UNIX中。
      DB2
      DB2具有很好的并行性。DB2把数据库管理扩充到了并行的、多节点的环境。数据库分区是数据库的一部分,包含自己的数据、索引、配置文件、和事务日志。数据库分区有时被称为节点或数据库节点。
      安全性
      SQL server
      没有获得任何安全证书。
      Oracle Server
      获得最高认证级别的ISO标准认证。
      DB2
      获得最高认证级别的ISO标准认证。
      性能
      SQL Server
      多用户时性能不佳
      Oracle
      性能最高, 保持WindowsNT下的TPC-D和TPC-C的世界记录。
      DB2
      适用于数据仓库和在线事务处理,性能较高。
      客户端支持及应用模式
      SQL Server
      C/S结构,只支持Windows客户,可以用ADO,DAO,OLEDB,ODBC连接。
      Oracle
      多层次网络计算,支持多种工业标准,可以用ODBC,JDBC,OCI等网络客户连接。
      DB2
      跨平台,多层结构,支持ODBC,JDBC等客户。
      操作简便
      SQL Server
      操作简单,但只有图形界面。
      Oracle
      较复杂, 同时提供GUI和命令行,在Windows NT和Unix下操作相同。
      DB2
      操作简单,同时提供GUI和命令行,在Windows NT和Unix下操作相同。
      使用风险
      SQL Server
      完全重写的代码,经历了长期的测试,不断延迟,许多功能需要时间来证明。并不十分兼容早期产品。使用需要冒一定风险。
      Oracle
      长时间的开发经验,完全向下兼容。得到广泛的应用。完全没有风险。
      DB2
      在巨型企业得到广泛的应用,向下兼容性好。风险小。

  • IBM DB2数据库SQL编码优化基础教程介绍

    2009-02-02 16:44:45

    当要保证用IBM DB2 Universal Database(DB2 UDB)和Borland工具(如 Delphi、C++Builder或Kylix)构建的企业应用程序拥有最优性能时,程序员可以利用 DB2 优化器的能力来处理即使是“难以处理的”SQL 语句并给出有效的存取路径。尽管如此,拙劣编码的 SQL 和应用程序代码仍可能给您带来性能问题,通过学习几条基本准则可以轻易地避免这些问题。我将向您演示 DB2 优化器的工作方式,并提供编写能发挥优化器最大效率的 SQL 的准则。但即使拥有了 DB2 的优化能力,编写有效的SQL语句仍可能是一件复杂的事情。如果程序员和开发人员还不熟悉关系数据库环境,这件事就尤其显得棘手。因此,在我们深入研究编码SQL以获得最佳性能的细节之前,先花一些时间来回顾 SQL 基础知识。

      基础知识

      由于 SQL 与过程化语言不同,它提供了更高的抽象级别,因此它可以让程序员把精力集中到他们需要 什么样的数据,而不是如何检索数据。您不必使用嵌入式数据导航指令来编码 SQL。DB2 会分析 SQL,并“在幕后”制定数据导航指令。这些数据导航指令叫作存取路径。让 DBMS 确定到数据的最优存取路径解除了程序员肩上沉重的负担。此外,数据库可以更好地理解它存储的数据的状态,从而可以生成到数据的更有效和动态的存取路径。其结果就是适当使用的 SQL 可以用于更快的应用程序开发。

      另一个 SQL 特性是它不仅仅是一种查询语言。您还可以使用它来定义数据结构;控制对数据的访问;以及插入、修改和删除数据的发生。通过提供一种公共语言,SQL 简化了 DBA、系统程序员、应用程序员、系统分析员和最终用户之间的通信。当项目的所有参与者都使用同一种语言时,他们之间所建立起来的协作就可以减少整体系统开发时间。

      历史证明,保证 SQL 成功的最重要的一个特性就是它使用类似英语的语法轻松地检索数据的能力。理解这种语言比理解数据页面的结构和程序源代码要容易得多:

      SELECT LASTNAME

      FROM EMP

      WHERE EMPNO = ’000010’;

      想想看:当访问文件中的数据时,程序员必须编码指令来打开文件、开始一个循环、读取记录、检查 EMPNO 字段是否等于适当的值、检查文件结尾、回到循环的开头等。

      SQL 本来就是非常灵活的。它使用自由格式的结构,该结构可以让用户开发 SQL 语句来适合他们的需要。DBMS 在执行之前会分析每个 SQL 请求,以检查语法是否正确和优化该请求。SQL 语句不需要从任何给定的列中开始,您可以将它们串在一行中,或者把它们拆成几行。例如,以下这条单行的 SQL 语句与我前面使用的三行示例等价:

      SELECT LASTNAME FROM EMP WHERE EMPNO = ’000010’;

      SQL 的另一个灵活特性是您可以用许多形式不同但功能等价的方法来制定一个请求。例如:SQL 可以连接表或嵌套查询。您始终可以将嵌套查询转换成等价的连接。您可以在大量的函数和谓词中看到这一灵活性的其它示例。具有等价功能的特性的示例包括:

      BETWEEN vs <= / >=

      IN vs 一系列和 OR 配合的谓词

      INNER JOIN vs FROM 子句中串在一起并用逗号分隔的表

      OUTER JOIN vs 带有 UNION 的简单 SELECT 和相关的子查询

      CASE 表达式 vs 复杂的 UNION ALL 语句

      SQL 展示的这一灵活性并不总是称心的,因为形式不同但功能等价的 SQL 公式可以提供非常不同的性能。我将在本文的以后部分讨论该灵活性所造成的结果,并提供开发有效的 SQL 的准则。

      如我所说的,SQL 指定了要检索或操作什么数据,但没有指定数据库如何完成这些任务。这就使 SQL 本身变得很简单。如果您能够记得关系数据库的一次处理一个集合(set-at-a-time)的特点,您就开始掌握 SQL 的本质和性质了。一条 SQL 语句可以作用于多行。作用于一组数据而不需要建立如何检索和操作数据的能力将 SQL 定义成非过程化语言

      因为 SQL 是一种非过程化语言,所以一条语句可以代替一系列过程。同样,由于 SQL 使用集合级别的处理以及 DB2 优化查询来确定数据导航逻辑,所以这是可能的。有时,如果不使用 SQL 语句,一条或两条 SQL 语句可以完成的任务就需要完整的过程化程序来完成。

      优化器

      优化器是 DB2 的心脏和灵魂。它分析 SQL 语句并确定可以满足每条语句的最有效的存取路径(请参阅图 1)。DB2 UDB 通过解析 SQL 语句来确定必须访问哪些表和列,从而完成该操作。DB2 优化器然后查询存储在 DB2 系统目录中的系统信息和统计信息,以确定完成满足 SQL 请求所必需的任务的最佳方法。

      

      图1. 运行中的 DB2 优化

    优化器在功能上等价于一个专家系统。专家系统是一个标准规则集合,当与情境数据组合时,它返回一个“专家”意见。例如,医学专家系统采用一个规则集合,用来确定哪些药可以用于哪些疾病,将规则集与描述疾病症状的数据组合,并将知识库应用于输入症状的列表。DB2 优化器会根据存储在 DB2 系统目录中的情境数据和 SQL 格式的查询输入来生成对数据检索方法的专家意见。

      在 DBMS 中优化数据访问的概念是 DB2 最强大的能力之一。请记住,您访问 DB2 数据时应告诉 DB2 要检索什么,而不是如何检索。无论数据实际上是如何存储和操作的,DB2 和 SQL 都可以访问该数据。从物理存储特征中分离出访问标准叫作物理数据独立性。DB2 的优化器是完成该物理数据独立性的组件。

      如果您不要索引,DB2 仍然能够访问数据(尽管效率会降低)。如果将一列添加到正在被访问的表中,DB2 仍然可以在不更改程序代码的情况下操作数据。因为到 DB2 数据的物理存取路径并不是由程序员在应用程序中编码的,而是由 DB2 生成的,所以这种情况是完全有可能发生的。

      这个特点与非 DBMS 系统非常不同,在那种系统中,程序员必须知道数据的物理结构。如果有索引,程序员就必须编写适当的代码来使用该索引。如果某人删除了索引,程序就不能工作,除非程序员进行更改。而使用 DB2 和 SQL 就不必如此。这一灵活性完全归功于 DB2 自动优化数据操作请求的能力。

      优化器根据许多信息执行复杂的计算。要使优化器的工作方式直观化,可以将优化器想象成执行一个四步骤的过程:

      1、接收并验证 SQL 语句的语法。

      2、分析环境并优化满足 SQL 语句的方法。

      3、创建计算机可读指令来执行优化的 SQL。

      4、执行指令或存储它们以便将来执行。

      这个过程的第二步是最有趣的。优化器怎样决定如何以它的方式执行您可以发送的大量 SQL 语句?

      优化器有许多类型的优化 SQL 的策略。它如何选择在优化存取路径中使用这些策略中的哪一个?IBM 并没有发布优化器如何确定最佳存取路径的真正和深入的详细信息,但优化器是一个基于成本的优化器。这意味着优化器将始终尝试为每个查询制定减少总体成本的存取路径。要实现这个目标,DB2 优化器会应用查询成本公式,该公式对每条可能的存取路径的四个因素进行评估和权衡:CPU 成本、I/O 成本、DB2 系统目录中的统计信息和实际的 SQL 语句。

      性能准则

      因此,只要记住关于 DB2 优化器的信息,您就可以实现这些准则以便获得更好的 SQL 性能:

      1) 使 DB2 统计信息保持最新 :如果没有存储在 DB2 系统目录中的统计信息,优化器在优化任何事物时都会遇到困难。这些统计信息向优化器提供了与正在被优化的 SQL 语句将要访问的表状态相关的信息。存储在系统目录中的统计信息的类型包括:

      关于 表的信息,包括总的行数、关于压缩的信息和总页数;

      关于 列的信息,包括列的离散值的数量和存储在列中的值的分布范围;

      关于 表空间的信息,包括活动页面的数量;

      索引的当前状态,包括是否存在索引、索引的组织(叶子页的数量和级别的数量)、索引键的离散值的数量以及是否群集索引;

      关于表空间和索引节点组或分区的信息。

      当执行 RUNSTATS 或 RUN STATISTICS 实用程序时,统计信息就会填充 DB2 系统目录。您可以从控制中心(Control Center)、批处理作业或通过使用命令行处理器来调用该实用程序。一定要与您的 DBA 一起工作以确保在适当的时候积累统计信息,尤其是在生产环境中。

      2) 构建适当的索引 :也许您为保证最佳 DB2 应用程序性能而可以做的最重要的事就是根据应用程序使用的查询为您的表创建正确的索引。当然,说总比做更容易。但我们可以从一些基础开始。例如,考虑以下这条 SQL 语句:

      SELECT LASTNAME, SALARY

      FROM EMP

      WHERE EMPNO = ’000010’

      AND DEPTNO = ’D01’

      什么索引会对这个简单查询有作用?首先,考虑您可以创建的所有可能的索引。您的第一个简短列表可能看起来如下:

      EMPNO 上的 Index1

      DEPTNO 上的 Index2

      EMPNO 和 DEPTNO 上的 Index3

      这是一个好的开始,Index3 可能是最好的。它让 DB2 使用索引来立即查找满足 WHERE 子句中的两个简单谓词的行。当然,如果您已经有许多关于 EMP 表的索引,您也许应该检查再创建另一个关于表的索引所带来的影响。要考虑的因素包括:

      修改影响 :DB2 将自动维护您创建的每个索引。这表示对该表的每个 INSERT 和每个 DELETE 都将不仅在表中插入和删除,而且会在其索引中插入和删除。如果您对在索引中的列的值进行 UPDATE 操作,那么您还更新了该索引。因此索引加快了检索过程的速度,但减慢了修改的速度。

      现有索引中的列 :如果在 EMPNO 或 DEPTNO 上已经有了一个索引,那么创建另一个关于该组合的索引也许并不明智。但是,更改另一个索引以添加缺少的列也许可以起作用。但也不一定,因为索引中列的顺序也许会根据查询而有很大差异。例如,考虑以下查询:

      SELECT LASTNAME, SALARY

      FROM EMP

      WHERE EMPNO = ’000010’

      AND DEPTNO > ’D01’;

      在这种情况下,在索引中应该首先列出 EMPNO。然后列出 DEPTNO,从而允许 DB2 对第一列(EMPNO)执行直接索引查找,然后针对大于号扫描第二列(DEPTNO)。

      而且,如果已经存在关于这两列的索引(一个关于 EMPNO,一个关于 DEPTNO),DB2 可以使用它们来满足该查询,因此创建另一个索引也许是没有必要的。

    这种特定查询的重要性:查询越重要,那么您可能就越应该通过创建索引来进行调优。如果您正在编码 CIO 要每天都运行的查询,那么您应该确保它提供最佳性能。因此,为该特定查询构建索引是很重要的。反之,职员的查询也许就没有必要看得那么重,所以也许应该利用现有索引来执行查询。当然,决定取决于应用程序对业务的重要性 - 而不只是用户的重要性。

      索引设计涉及的内容比到目前为止我所讨论的要多得多。例如,您也许要考虑索引重载以实现仅索引访问(index-only access)。如果 SQL 查询要寻找的所有数据都包含在索引中,那么 DB2 也许只使用索引就可以满足该请求。请考虑我们前面的 SQL 语句。给定了关于 EMPNO 和 DEPTNO 的信息,我们要寻找 LASTNAME 和 SALARY。我们还从创建关于 EMPNO 和 DEPTNO 列的索引开始。如果我们在索引中还包含了 LASTNAME 和 SALARY,我们就不再需要访问 EMP 表,因为我们需要的所有数据都已经在索引中。该技术可以大大提高性能,因为它减少了 I/O 请求的数量。

      请记住:使每个查询成为仅索引访问是不谨慎,甚至也是不可能的。您应该谨慎使用该技术以便用于特别棘手或重要的 SQL 语句。

      SQL 编码准则

      当您编写访问 DB2 数据的 SQL 语句时,要确保遵循以下三个编码 SQL 的准则以获得最佳性能。当然,SQL 性能是一个复杂的话题,而且了解 SQL 的执行方式的每一个细微差别可能要花一生的时间。但是,这些简单的规则可以使您进入开发高性能 DB2 应用程序的正轨。

      第一条规则是始终在每条 SQL SELECT 语句的 SELECT 列表中只提供 确实需要检索的那些列 。另一种说法就是“不要使用 SELECT *”。简写 SELECT * 表示您要检索正在被访问的表中的所有列。这适用于“快捷但不恰当的方式获得的“(quick and dirty)查询,但却是应用程序的坏实践,因为:

      DB2 表在将来可能需要更改,以包括附加列。SELECT * 也会检索那些新的列,而如果没有进行费时的更改,您的程序也许无法处理附加的数据。

      DB2 将为被请求返回的每一列消耗附加资源。如果程序不需要数据,它就不会寻找它。即使程序需要每一列,最好根据 SQL 语句中的名称来显式地寻找每一列,以便增加清晰度和避免以前犯的错误。

      不要寻找您已经知道的东西 。这听起来似乎显而易见,但大多数程序员都曾经违反过这条规则。举一个典型的示例,考虑以下 SQL 语句有什么错误:

      SELECT EMPNO, LASTNAME, SALARY

      FROM EMP

      WHERE EMPNO = ’000010’;

      放弃吗?问题是 EMPNO 已经包含在 SELECT 列表中。您已经知道了 EMPNO 将等于值“000010”,因为那就是 WHERE 子句要 DB2 做的事。但在 WHERE 子句中列出了 EMPNO,DB2 还会尽职地检索该列。这会产生附加开销,从而降低性能。

      在 SQL 中 使用 WHERE 子句过滤数据,而不是在程序中到处使用它进行过滤。这也是新手容易犯的错误。在 DB2 将数据返回到程序之前,最好由 DB2 过滤数据。这是因为 DB2 使用附加 I/O 和 CPU 资源来获取每一行数据。传递到程序的行越少,SQL 的效率就越高:

      SELECT EMPNO, LASTNAME, SALARY

      FROM EMP

      WHERE SALARY > 50000.00;

      与只读取所有数据而不使用 WHERE 子句,然后在程序中检查 SALARY 是否大于 50000.00 的做法相比,该 SQL 更好。

      使用参数化查询 。参数化 SQL 语句包含了变量,也称作参数(或参数标记)。典型的参数化查询使用这些参数来代替文字值,因此 WHERE 子句条件可以在运行时更改。通常程序被设计成最终用户可以在运行查询之前提供参数的值。这允许使用一个查询根据提供给参数的不同的值返回不同的结果。

    参数化查询的主要性能好处是优化器可以制定在重复执行语句时能够再使用的存取路径。与每次 WHERE 子句中需要一个新值就发出一条全新的 SQL 语句相比,这可以给程序增加很大的性能收益。

      但是,这些规则并不是 SQL 性能调优的最终和最高目标 - 决不是。您可能需要附加的、深入的调优。但遵循前面的规则将确保您不会犯降低应用程序性能的“新手”错误。

      特定数据库应用程序开发技巧

      无论您使用的是 Delphi、C++Builder 还是 Kylix,某些技巧和准则将帮助您确保在访问 DB2 数据时获得好的性能。例如,在某些情况下,使用 dbExpress TM来代替 ODBC/JDBC 或 ADO 可以提高查询性能。dbExpress 是用于从 Delphi(或 Borland Kylix™)处理动态 SQL 的跨平台接口。

      要确保在您的应用程序中经常发出 COMMIT 语句。COMMIT 语句控制工作单元。发出 COMMIT 会将自上一个 COMMIT 语句之后的所有工作“永远”记录到数据库中。在发出 COMMIT 之前,可以使用 ROLLBACK 语句回滚工作。当修改数据(使用 INSERT、UPDATE 和 DELETE)但没有发出 COMMIT 时,DB2 将在数据上加一把锁并保持该锁 - 这把锁会使其它应用程序在等待检索被锁住的数据时超时。通过在工作完成时发出 COMMIT 语句,并且确保数据是正确的,就释放了该数据以供其它应用程序使用。

      另外,构建应用程序时要考虑使用情况。例如,当某个特定查询返回几千行给最终用户时,要慎重处理。对于在程序和最终用户之间的在线交互,很少会用到几百行以上的数据。您可以在 SQL 语句上使用 FETCH FIRST nROWS ONLY 子句来限制返回到查询的数据量。例如,考虑以下查询:

      SELECT EMPNO, LASTNAME, SALARY

      FROM EMP

      WHERE SALARY > 10000.00

      FETCH FIRST 200 ROWS ONLY;

      该查询将只返回 200 行。如果有超过 200 行符合条件也没有关系;如果您尝试从查询中 FETCH(访存)超过 200 行,DB2 将用 +100 SQLCODE 表明数据结束。当您想要限制返回给程序的数据量时,这种方法很有用。

      DB2 支持另一个名为 OPTIMIZE FOR nROWS 的子句,该子句不限制要返回给游标的行数,但从性能角度看可能是有帮助的。使用 OPTIMIZE FOR nROWS 子句告诉 DB2 如何处理 SQL 语句。例如:

      SELECT EMPNO, LASTNAME, SALARY

      FROM EMP

      WHERE SALARY > 10000.00

      OPTIMIZE FOR 20 ROWS;

      这告诉 DB2 尝试尽快访存前 20 行。如果您的 Delphi 应用程序在显示从数据库检索出来的数据行时每次显示 20 行,那么这将非常有用。

      对于只读游标,使用 FOR READ ONLY 子句确保游标无歧义。Delphi 不能在 DB2 游标中执行位置更新,因此将 FOR READ ONLY 附加到每条 SELECT 语句后面可以使游标成为无歧义的只读游标,从而对 DB2 有所帮助。例如:

      SELECT EMPNO, LASTNAME, SALARY

      FROM EMP

      WHERE SALARY > 10000.00

      FOR READ ONLY;

      结束语

      了解 SQL 编码以获得最佳性能的基础知识将使您的 Delphi 企业应用程序的性能立即得到增长。但我只揭露了冰山一角。您需要学习日益增多的 SQL 的复杂类型,包括连接、子选择和联合等。您还需要学习如何最好地编写这些 SQL 语句以及如何发现 DB2 选择的存取路径来满足您的 SQL 请求。确实,还有许多要学习。但是您已经学习了一些如何最大限度地利用 DB2 SQL 的初步知识,尽情地享用这些知识吧。

  • 一段寻找DB2数据库建表节点分布不均衡表的代码,unix shell实现,对DBA来说及其有用

    2009-02-02 16:38:51

    #!/bin/sh
    if [ ! $# -eq 1 ]
       then
               print "Usage: $0 tabspacename"
               exit
    fi

    db2 connect reset > /dev/null
    db2 connect to DATABASE user USER using PASSWORD
    db2 "select tabname from syscat.tables where tbspace='$1'">tab.list
    while read TABNAME
    do
    # get partitioning key
    db2look -e -d sccrm -t $TABNAME -e > .tmp
    key=`cat .tmp | grep "PARTITIONING KEY" | awk -F\" '{print $2}' | sed -e "s/\"//g" `
    key_out=\(${key}\)
    echo $key
    echo $key_out

    echo  "TABLE: ${TABNAME} select nodenumber $key_out ,count(*)  from ${TABNAME} group by  nodenumber $key_out  "
    db2  " select 'tablename , ${TABNAME} ', nodenumber $key_out ,count(*) as s  from ${TABNAME} group by  nodenumber $key_out  o
    rder by s  "
    done<tab.list
    db2 connect reset > /dev/null

我的存档

数据统计

  • 访问量: 7418
  • 日志数: 3
  • 建立时间: 2009-02-02
  • 更新时间: 2009-02-02

RSS订阅

Open Toolbar