版本:Oracle 11.2.0.4.0
操作系统:linux redhat 6.4
场景:
最近重新读梁敬彬老师 基于案例学习SQL优化课程,在忽略SQL改造等价性 在案例中有一个 看似不等,其实相等的 案例,在巡检目前生产环境也有相似情况,特记录下。
begin
select count(*) into v_cnt from t1 ;
if v_cnt>0
then …A逻辑….
else
then …B逻辑…..
End;
我来翻译一下这段需求:
获取t1 表的记录数,判断是否大于0,如果大于0走A逻辑,否则就走B逻辑。
因此代码就如上所示来实现了。真正的需求是这样吗?
其实应该是这样的:只要T1表有记录就走A逻辑,否则走B逻辑。
两者有区别吗?其实区别还是很大的,前者可是强调获取记录数,我们是不是一定要遍历整个表得出一个记录数才知道是否大于0?
真正需求的理解可以让我们这样实现,只要从T1表中成功获取到第一条记录,就可以停止检索了,表示该表有记录了,难道事实不是这样?
因此原先的SQL1 从Select count(*) from t1; 被改造为:
Select count(*) from t1 where rownum=1;
begin
select count(*) into v_cnt from t1 where rownum=1;
if v_cnt=1
then …A逻辑….
else
then …B逻辑…..
End;
生产环境运行脚本:
/*增加对于PJOB类作业如果数据为0的情况,记录日志实现如下*/
DECLARE
V_ROWNUM NUMBER;
BEGIN
V_ROWNUM:=0;
SELECT COUNT(1) INTO V_ROWNUM
FROM MNG.SYS_PJOB_MONITOR_TMP T
WHERE T.PJOB_NAME = 'Q_O_ZQ_SEC_INTERBANKINFO' ;
IF V_ROWNUM > 0 THEN
INSERT INTO MNG.SYS_PJOB_MONITOR_LOG NOLOGGING
SELECT PJOB_NAME,
T.ETL_DATE ETL_DATE,
T.START_DATE,
SYSDATE END_DATE,
'OK' PJOB_STATUS,
COUNT(1 ) PJOB_COUNT,
'ZQ' DATE_SOURCE,
'O' PJOB_MARK
FROM MNG.SYS_PJOB_MONITOR_TMP T
WHERE T.PJOB_NAME = 'Q_O_ZQ_SEC_INTERBANKINFO'
GROUP BY T.START_DATE,
T.ETL_DATE,
PJOB_NAME,
DATE_SOURCE,
PJOB_MARK;
ELSE
INSERT INTO MNG.SYS_PJOB_MONITOR_LOG NOLOGGING
(PJOB_NAME,
ETL_DATE,
START_DATE,
END_DATE,
PJOB_STATUS,
PJOB_COUNT,
DATE_SOURCE,
PJOB_MARK)
VALUES
('Q_O_ZQ_SEC_INTERBANKINFO',
'',
SYSDATE,
SYSDATE,
'OK',
'0',
'ZQ',
'O');
END IF;
COMMIT;
DELETE /*+PARALLEL(8) NOLOGGING */ FROM MNG.SYS_PJOB_MONITOR_TMP G WHERE G.PJOB_NAME = 'Q_O_ZQ_SEC_INTERBANKINFO' ;
COMMIT;
END;
修正:
/*增加对于PJOB类作业如果数据为0的情况,记录日志实现如下*/
/*增加对于PJOB类作业如果数据为0的情况,记录日志实现如下*/
DECLARE
V_ROWNUM NUMBER;
BEGIN
V_ROWNUM:=0;
SELECT COUNT(1) INTO V_ROWNUM
FROM MNG.SYS_PJOB_MONITOR_TMP T
WHERE T.PJOB_NAME = 'Q_O_ZQ_SEC_INTERBANKINFO' rownum=1;
总结:
SQL 优化的一大技能便是等价改写,而等价的改写很大程度上都是依赖于对需求的理解。做优化前多了解需求。