【发布时间】:2011-02-16 21:56:22
【问题描述】:
我有一个使用 EXECUTE IMMEDIATE 调用的存储过程。我面临的问题是,当我直接调用该过程与使用 EXECUTE IMMEDIATE 调用该过程时,解释计划是不同的。这导致执行时间增加了 5 倍。计划之间的主要区别在于,当我使用立即执行时,优化器不会取消嵌套子查询(我使用的是 NOT EXISTS 条件)。对于大多数查询,我们在此处使用基于规则的优化器,但这个提示使用索引,因此正在使用 CBO(但是,我们不收集表上的统计信息)。我们正在运行 Oracle9i Enterprise Edition Release 9.2.0.4.0 - 64bit Production。
示例: 快速:
begin
package.procedure;
end;
/
慢:
begin
execute immediate 'begin package.' || proc_name || '; end;';
end;
/
查询:
SELECT /*+ INDEX(A IDX_A_1) */
a.store_cd,
b.itm_cd itm_cd,
CEIL ( (new_date - a.dt) / 7) week_num,
SUM (a.qty * b.demand_weighting * b.CONVERT) qty
FROM a
INNER JOIN
b
ON (a.itm_cd = b.old_itm_cd)
INNER JOIN
(SELECT g.store_grp_cd, g.store_cd
FROM g, h
WHERE g.store_grp_cd = h.fdo_cd AND h.fdo_type = '1') d
ON (a.store_cd = d.store_cd AND b.store_grp_cd = d.store_grp_cd)
CROSS JOIN
dow
WHERE a.dt BETWEEN dow.new_date - 91 AND dow.new_date - 1
AND a.sls_wr_cd = 'W'
AND b.demand_type = 'S'
AND b.old_itm_cd IS NOT NULL
AND NOT EXISTS
(SELECT
NULL
FROM f
WHERE f.store_grp_cd = a.store_cd
AND b.old_itm_cd = f.old_itm_cd)
GROUP BY a.store_cd, b.itm_cd, CEIL ( (dow.new_date - a.dt) / 7)
好的解释计划:
OPERATION OPTIONS OBJECT_NAME OBJECT_TYPE ID PARENT_ID 选择语句 0 按 1 0 分组 嵌套循环 2 1 哈希加入反 3 2 按索引 ROWID 访问表 H 4 3 嵌套循环 5 4 嵌套循环 6 5 嵌套循环 7 6 表访问完全 B 8 7 按索引 ROWID 访问表 A 9 7 索引范围扫描 IDX_A_1 唯一 10 9 索引唯一扫描 G 唯一 11 6 索引范围扫描 H_UK 唯一 12 5 表访问完全 F 13 3 表访问完全 DOW 14 2
糟糕的解释计划:
OPERATION OPTIONS OBJECT_NAME OBJECT_TYPE ID PARENT_ID 选择语句 0 按 1 0 分组 嵌套循环 2 1 嵌套循环 3 2 嵌套循环 4 3 嵌套循环 5 4 表访问完全 B 6 5 按索引 ROWID 访问表 A 7 5 索引范围扫描 IDX_A_1 唯一 8 7 表访问完全 F 9 8 索引唯一扫描 G 唯一 10 4 按索引 ROWID 访问表 H 11 3 索引范围扫描 H_UK 唯一 12 11 表访问完全 DOW 13 2
在错误的解释计划中,子查询没有被取消嵌套。通过向子查询添加 no_unnest 提示,我能够重现错误的计划;但是,我无法使用 unnest 提示重现良好的计划(当使用执行立即运行该过程时)。优化器在使用立即执行而不是未嵌套提示时正在考虑其他提示。
仅当我使用立即执行来调用该过程时才会出现此问题。如果我在查询本身上使用 execute immediate,它会使用好的计划。
【问题讨论】:
-
我认为基于规则的 oprimizer 应该是一致的。也许添加一个提示,看看这是否也会改变计划 - 以验证 RBO 是否实际生效......
-
我们已经提示在查询中使用索引,那么这是否会导致使用 CBO 代替查询?即便如此,我尝试向子查询添加不嵌套的提示,但它似乎不尊重提示。
-
索引提示不会导致使用 CBO。您可以使用 FIRST_ROWS 或 ALL_ROWS 提示强制使用 CBO,或使用 RULE 提示强制使用 RBO。也许您应该发布实际的 SQL 查询和您看到的两个不同的计划。
-
请发布实际查询和生成的计划,然后也许我们可以提供建议。一件事:如果你的桌子上没有统计数据,我的经验是,CBO 几乎肯定会给你一个糟糕的计划。您运行的是哪个版本的 Oracle?
-
我在帖子中包含了查询和两个解释计划。
标签: oracle performance sql-execution-plan execute-immediate