Posted on 2008-09-10 10:42
Prayer 阅读(234)
评论(0) 编辑 收藏 引用 所属分类:
数据库,SQL 、
C/C++ 、
DB2
----DB2应用程序使用SQL通讯区(SQLCA)将信息返回到程序中,有些信息是有用的,有些不是;有些是有意义的,有些不是。如果能它们区分开来,那么我们可以利用SQLCA信息来提高程序代码的效率,减少DB2调用的开销,从而简化程序逻辑,提高性能。
SQLCODE
----SQLCA中最常使用的域是SQLCODE,许多程序员知道在每一次调用DB2以后都应该检查SQLCODE,以确定该调用是否成功。大多数程序者会把SQLCODE是否为+0,作为成功调用的标志。同时还会检查SQLCODE是否为+100,作为文件结束的标志(没有记录或没有更多的记录)。对于其他的SQLCODE,不管是正值或负值,程序一般都执行错误处理例程,结束程序或事务。但是,SQLCODE为负值并不一定表示错误非常严重,以至于要结束程序。并且,某些SQLCODE为正值时,可以有非常有趣的方式利用它。
----我们可以对一些负的SQLCODE定制响应代码,以减少CPU启动和运行程序的开销。例如,可以编写程序处理-911(不能获得要求的锁,事务被回滚),程序可以简单的重试,直到成功或重试计数到某一个值。但应该注意的是:出于数据完整性的理由,重试必须从程序恰当的执行点开始。重试点不一定是重新执行失败的语句,尤其是对那些隐式地回滚事务的SQLCODE。
----负的SQLCODE通常代表程序执行中的意外错误,但某些情况下,可以编写特定的SQL语句故意使程序获得负值返回,然后通过测试预期的负值,简化逻辑判断的代码,从而减少DB2页面读取的数目。
----例如,某一个大电话公司有两种类型的发票:一种给只有一条电话线的住宅用户,另一种给有多条电话线的公司用户。在处理每一个客户时,处理客户发票的程序对该客户做一次COUNT(电话账单表非常大)。如果COUNT的结果为一,则程序转入住宅用户发票格式处理,如果COUNT的结果大于一,则转入公司用户发票格式处理。最后,在发票格式化的过程中,每个客户的记录又再次被读入。在这种程序逻辑下,每一个客户的账单信息不必要地读入了两次,包括即些非常大的商业客户,他们有几百条电话线。
----其实可以将程序逻辑修改一下,对每一个客户做的简单的选择(SELECT ...INTO ),然后测试返回的SQLCODE是否为+0(即仅有一条电话线,转入住宅用户发票格式),或者-811(多于一条电话线,单选操作失败,转入公司用户发票格式)。显而易见,这样可以节省大量的时间。而其他的解决办法或者需要改变表结构,并且占用数据库管理员和程序员更多的时间。
----另一个利用SQLCODE来提高性能的例子如下:每一个输入事务有两种操作,如果有匹配记录,则更新它,否则插入一条新记录。效率低下的程序可能会首先做一个选取(SELECT),判断记录是否存在。然后当SQLCODE为+0时,已经有的记录会再次被读入并更新;当SQLCODE为+100时,插入新的记录。更有效率的方法应该首先尝试最常发生的情况。如果更新比插入更频繁,则首先尝试更新,并检查SQLCODE是否为+0(成功更新了该记录),如果SQLCODE为+100(未发现匹配的记录),再插入该记录。相反,如果插入比更新频繁,则首先可以执行插入,并检查SQLCODE是否为+0(成功插入),或者-803(发现重复记录),这时再更新该记录。任何一种方法都可以消除不必要的重复选择开销。
SQL警告
----大多数程序都忽略SQL警告,但这样做并不合适,因为警告对于测潜在问题和简化程序逻辑很有帮助,所以虽然警告不是严重信息,但不应该被忽略。
----在SQLCA中有两个警告信息的指示:一个是SQLCODE大于+100;另一个是SQLWARN0域为W。当任何一个出现时,就表明在上一次调用时DB2发生了一些值得注意的事情,虽然DB2返回了数据,但是可能与预期的有出入。当SQLWARN0是W时,DB2也在其他SQLWARNn域提供了该问题的有用信息。
----试举一例,下面这条SELECT语句中带有数学表达式:
----SELECT empid,comm/salary INTO :hvempid, :hvcalc FROM EMPLOYEE
----如果在某一条记录碰上了数学异常,例如被0除,则返回代码-802。没有数据返回,也不知道是哪一条记录导致了该错误。但是,如果为数学表达式提供空值指示器宿主变量,改为:
----SELECT empid,comm/salary INTO :hvempid,:hvcalc :hvind FROM EMPLOYEE
----DB2将指示器变量设置为-2,并且返回SQLCODE为+802。这样程序将获得返回的empid,从而可以判断哪个雇员的记录造成了异常,程序也不需要终止。
----测试SQLWARN0是否为W也同样有用。例如,如果程序将字符串数据选取到宿主变量中,而该变量的长度不足以容纳整个字符串,则SQLCODE为+0,但数据被截断了。通过提供指示器变量可以解决这个问题,DB2把SQLWARN0设为W,SQLWARN1设为W,并且将指示器变量设为原始串的长度,通过使用指示器变量中的值就可以判断数据串的最大长度。
SQLERRD(3)
----SQLERRD数组的第三项是SQLCA中最有用的域之一。当成功地完成了插入、更新或删除以后,该域被设置为插入、更新或删除的记录数。如果不知道SQLCA中含有这样的信息而程序又需要它,则不得不首先做一下COUNT。更糟糕的是,如果程序逻辑是将每一条记录选取到程序中,增加计数值,然后逐个地插入、更新或删除每一条记录,这样就丧失了集合操作的好处。这时最好的办法就是做SQL多记录插入、更新或删除,然后检查SQLERRD(3),获取需要的计数。
----然而也有例外的情况,首先,在SQL删除语句后,SQLERRD(3)并不包括DB2参照完整性而导致的级连删除的记录数。其次,从分段的表空间中海量删除(即DELETE语句无WHERE子名),在SQLERRD(3)以-1表示。因为DB2通过更新的记录表空间映射页来进行分段表空间的海量删除,实际的记录并未被读取,因此无法计数。除了这两个例外的情况,SQLERRD(3)可以用来节省DB2的读取操作。
----SQLCA共有24个域,详细内容可以参阅SQL参考手册的附录C,通过上述的例子说明,SQLCA中有用的域不仅是SQLCODE,灵活使用其他域,可以简化程序逻辑,减少DB2调用次数,从而提高程序性能。