【发布时间】:2011-11-22 22:33:20
【问题描述】:
我遇到了一个需要永远执行的存储过程的问题。它非常大,我可以理解我需要一些时间,但这个持续了将近 20 分钟。
经过一些调试和研究,我注意到替换了WHERE 子句的这一部分;
((p_DrumNo IS NULL) OR T_ORDER.ORDER_ID IN (SELECT ORDER_ID FROM ORDERDELIVERY))
产生了巨大的变化。因此,只要 p_DrumNo 为 NULL,程序就可以正常工作,或者我修改上述内容以不检查 p_DrumNo 是否为 NULL;
(T_ORDER.ORDER_ID IN (SELECT ORDER_ID FROM ORDERDELIVERY))
WHERE 子句的目标是过滤 p_DrumNo 上的结果集(如果它被传递到存储过程)。 WHERE 子句随后会继续处理更多条件,但这个特定条件会暂停查询。
ORDERDELIVERY 只是一个~临时表,其中包含与参数 p_DrumNo 相关的 ORDER_ID。
这个简单的 IS NULL 检查怎么会造成如此大的影响?这可能与 OR 与子查询一起使用有关,但我不明白为什么子查询本身可以正常工作。
提前致谢!
更新 [2011-09-23 10:13]
我已将问题分解为显示相同行为的小查询;
示例 A
SQL 查询
SELECT * FROM T_ORDER WHERE
('290427' IS NULL OR ORDER_ID IN (SELECT ORDER_ID FROM T_ORDER WHERE ORDERNO LIKE '290427%') );
执行计划
OPERATION OBJECT_NAME OPTIONS COST
------------------------------------------------------------
SELECT STATEMENT 97
FILTER
TABLE ACCESS T_ORDER FULL 95
TABLE ACCESS T_ORDER BY INDEX ROWID 2
INDEX PK_ORDER UNIQUE SCAN 1
示例 B
SQL 查询
SELECT * FROM T_ORDER WHERE
( ORDER_ID IN (SELECT ORDER_ID FROM T_ORDER WHERE ORDERNO LIKE '290427%') );
执行计划
OPERATION OBJECT_NAME OPTIONS COST
------------------------------------------------------------
SELECT STATEMENT 4
NESTED LOOPS 4
TABLE ACCESS T_ORDER BY INDEX ROWID 3
INDEX IX_T_ORDER_ORDERNO RANGE SCAN 2
TABLE ACCESS T_ORDER BY INDEX ROWID 1
INDEX PK_ORDER UNIQUE SCAN 0
正如大家所见,第一个查询(示例 A)进行全表扫描。关于如何避免这种情况的任何想法?
【问题讨论】:
-
你能把这两种情况下的完整SQL语句和查询计划贴出来吗?
OrderDelivery是全局临时表吗?还是数据是瞬态的永久表?这个谓词的选择性如何? -
OrderDelivery 是游标内的临时表。我宁愿不包括整个过程,但我已经用一个例子更新了我的问题。谢谢
标签: oracle optimization stored-procedures parameters