我有一个参数化查询。根据参数值,最佳查询计划会有很大差异。这就是麻烦:Oracle使用第一次查询调用的计划进行后续调用,导致性能下降。我通过动态SQL来处理它,但这种方式远非优雅。所以问题是:有没有办法告诉Oracle必须重新计算查询计划?
答案 0 :(得分:4)
如果查询计划确实在参数值上发生了显着变化,那么您可能不应该对此参数使用绑定变量。
该参数可以使用多少个不同的值?如果只有少数几个,那么最终会得到一些查询计划(每个值一个),这些计划可能会很好地运行并且可以重复使用。
或者你可以在SQL语句中使用注释“/ *这是VALUE BRACKET ONE * /”来分隔它们(或者查询分析器提示,如果你想知道哪些是合适的,比如/ * + CARDINALITY * /可能适用于此处。)
无论哪种方式,我认为您希望拥有单独的SQL语句,以便您可以在Statspack和朋友中获得单独的报告,因为看起来您真的想要微调该查询。
答案 1 :(得分:2)
对于Oracle 10g,我们将在查询中选择任何表并执行
GRANT SELECT ON table1 TO user1;
这会使引用此表的任何查询的计划无效。当然,您可能希望选择对其他查询影响最小的表。有关详细信息和示例列表,另请参阅this page。
答案 2 :(得分:2)
如果您真的想每次都生成一个新的查询计划,只需在thilo建议中添加一个唯一的评论
select /* SQLID=1234 */ 1 from dual;
select /* SQLID=1235 */ 1 from dual;
这些应该会产生独特的计划。
我非常怀疑是否需要这样做,在尝试解决优化问题之前,你应该非常确定你的统计数据没有错误。
答案 3 :(得分:2)
优化器使用的一个东西是相关列上的直方图。如果您正在使用绑定变量,并且相关列上有直方图,则计划可能会根据参数值而更改。第一个计划将保留在共享池中,并将用于所有值。
如果你不想这样,那么你可以使用文字而不是绑定(如果你没有太多版本的同一个sql)。或者您可以删除直方图,删除直方图可确保独立于绑定参数值,将生成相同的计划。
每次执行都会使sql失效并不是一个好主意。根据这个sql的使用频率,它可能会导致新的问题,比如硬解析导致的锁存问题。
答案 4 :(得分:2)
有没有办法告诉Oracle必须重新计算查询计划?
您可以为不同的执行计划创建多个OUTLINE
,并使用OUTLINE CATEGORIES
选择要使用的执行计划:
CREATE OUTLINE ol_use_nl
FOR
SELECT *
FROM mytable1 mt1
JOIN mytable2 mt2
ON mt1.id = mt2.id
WHERE mt1.value BETWEEN :a AND :b
CATEGORY FILTERED;
/* Edit the outline to add USE_NL */
CREATE OUTLINE ol_use_nl
FOR
SELECT *
FROM mytable1 mt1
JOIN mytable2 mt2
ON mt1.id = mt2.id
WHERE mt1.value BETWEEN :a AND :b
CATEGORY UNFILTERED;
/* Edit the outline to add USE_HASH */
ALTER SESSION SET USE_STORED_OUTLINES = FILTERED;
SELECT *
FROM mytable1 mt1
JOIN mytable2 mt2
ON mt1.id = mt2.id
WHERE mt1.value BETWEEN 1 AND 2
/* This will use NESTED LOOPS */
ALTER SESSION SET USE_STORED_OUTLINES = UNFILTERED;
SELECT *
FROM mytable1 mt1
JOIN mytable2 mt2
ON mt1.id = mt2.id
WHERE mt1.value BETWEEN 1 AND 1000000
/* This will use HASH JOIN */
答案 5 :(得分:0)
你的问题是由于绑定变量偷看 - 为整个数据库关闭它可能会破坏其他东西,但你可以通过添加以下提示来关闭它只是这个查询:
/ * + opt_param('_ OPTIM_PEEK_USER_BINDS',FALSE)* /
答案 6 :(得分:0)
dbms_advanced_rewrite
,可以拦截SQL语句并更改此SQL语句。