存储过程优化方法
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
SQL存储过程出错处理
当存储过程出错时,你希望在日志里看到
SQLCODE = 119
还是
SQL0119N An expression starting with "CALL_AREA_CD" specified in a SELECT
clause, HA VING clause, or ORDER BY clause is not specified in the GROUP BY
clause or it is in a SELECT clause, HA VING clause, or ORDER BY clause with a
column function and no GROUP BY clause is specified.
呢?
其实DB2提供的GET DIAGNOSTICS语句可以获得文字消息:
DECLARE vMsgText VARCHAR (256);
-- 在存储过程的Exit Handler里面获取SQL错误的文本消息
GET DIAGNOSTICS EXCEPTION 1 vMsgText = MESSAGE_TEXT;
-- 参考DB2文档《SQL Reference Volume 2》
有了MESSAGE_TEXT,存储过程的调试和查错就方便多了。
声明临时表需要注意
指定合理的分区键
建议声明临时表时显式地指定分区键。
很多时候,DB2缺省选择的分区键是非常糟糕的。
例子:PRO_TM_USR_CONSUME_MO
CVS:/DSS代码/21软件代码/05基线代码/ETL/存储过程/
版本V01.400.000,CVS版本1.8
代码第75行
测试结果:对该SESSION临时表指定与目标表TM_USR_CONSUME_MO一致的分区键
后(只作此改动,其它代码不修改),原来跑6个小时的存储过程只需要不到2
个小时。
ETL.PRO_TM_CALLV AL_USR_MO_JF
尽量使关联表之间的分区键一致,并且关联条件包含所有的分区列。
目的是减少昂贵的分区间数据通信。
尽量使源表、目标表的分区键一致。
目的是减少昂贵的分区间数据通信。
定义必要的约束
创建约束的好处?
顾名思义,约束的作用就是对数据进行约束,DB2不允许把违反约束规则的数据插入到数据库。约束可以帮助我们尽早发现SQL中的逻辑错误。大部分程序缺陷是通过运行时的错误发现的,如果不定义任何约束,等于放弃了很多检测错误的机会。例:唯一约束可以避免重复运行同一个INSERT语句带来的恶果。
唯一约束、主键约束都是通过索引实施的,实际上它们无异于一个唯一索引。最常用的约束有
1.非空(NOT NULL)
2.唯一(UNIQUE)
ALTER TABLE
3.主键(PRIMARY KEY)
创建必要的索引
当需要从大量数据中选出少量数据时,我们需要索引。
提高SQL性能
RUNSTATS
执行RUNSTATS命令时要加上“WITH DISTRIBUTION”选项,统计各字段的取值分布情况,这也对Access Plan的选择有影响。
CREATE INDEX KF2.IDX_CNSM_GZ ON KF2.TW_USR_CNSM_RNK_GZ (CURRMO_AMT_FEE);
SELECT * FROM KF2.TW_USR_CNSM_RNK_GZ WHERE CURRMO_AMT_FEE = 100;
SELECT * FROM KF2.TW_USR_CNSM_RNK_GZ WHERE CURRMO_AMT_FEE <> 100;
建议RUNSTATS选项:
RUNSTATS ON
选择不存在于另一表的数据
看看以下三种写法
写法1:SELECT ... FROM A
WHERE A.key NOT IN (SELECT key FROM B);
写法2:SELECT ... FROM A
LEFT JOIN B ON A.key = B.key
WHERE B.key is null;
写法3:SELECT ... FROM A
WHERE NOT EXISTS
(SELECT 'x' FROM B WHERE A.key = B.key);
写法1采用NOT IN的写法。很不幸DB2对于NOT IN通常采用TBSCAN(表扫描),这是效率很差的写法。最佳写法是第三种写法,如果B.key上有索引,它可以不用fetch B表的数据就可以完成查询。第二种写法采用对外表B的is null判断进行过滤,效率稍差。
注:事实上,在DB2优化器的作用下,第二种写法与第三种写法的存取方案相关无几,只是第二种写法比第三种写法多了一步filter操作。
建议使用第3种写法,己使用第2种写法的代码也不必修改,因为其效率与第3种写法差不多。
例:
SELECT A.*
from EDS.TW_BCUST_200409 A LEFT OUTER JOIN KF2.TW_BCUST B ON
A.TM_INTRVL_CD =
B.TM_INTRVL_CD and A.CUST_ID =B.CUST_ID and
R_ID =
R_ID and A.BCUST_EFF_MO =B.BCUST_EFF_MO
WHERE B.TM_INTRVL_CD is null
SELECT *
from EDS.TW_BCUST_200409 A
where NOT EXISTS
(select 'x'
from KF2.TW_BCUST B
WHERE A.TM_INTRVL_CD =B.TM_INTRVL_CD and A.CUST_ID =B.CUST_ID
and R_ID =R_ID and A.BCUST_EFF_MO =
B.BCUST_EFF_MO)
这两种写法对应的存取方案:
RETURN RETURN
( 1) ( 1)
| |
BTQ BTQ
( 2) ( 2)
| |
FILTER HSJOIN
( 3) ( 3)
| / \
HSJOIN TBSCAN TBSCAN
( 4) ( 4) ( 5)
/ \ | |
TBSCAN TBSCAN Table: Table:
( 5) ( 6) EDS KF2
| | TW_BCUST_200409 TW_BCUST
Table: Table:
EDS KF2