Oracle查询优化:为什么我的第二个查询更快?

时间:2010-05-03 16:48:35

标签: sql performance oracle

我在Oracle查询中遇到了一些性能问题,所以我下载了Quest SQL Optimizer for Oracle的试用版,它进行了一些更改,大大提高了查询的性能。我不确定为什么推荐的查询有这样的改进;任何人都可以提供解释吗?


之前:

SELECT t1.version_id, 
       t1.id, 
       t2.field1, 
       t3.person_id, 
       t2.id 
  FROM table1 t1, 
       table2 t2, 
       table3 t3 
 WHERE t1.id = t2.id 
   AND t1.version_id = t2.version_id 
   AND t2.id = 123
   AND t1.version_id = t3.version_id 
   AND t1.VERSION_NAME <> 'AA' 
 order by t1.id
  • 计划费用:831
  • 经过时间:00:00:21.40
  • 记录数:40,717

后:

SELECT /*+ USE_NL_WITH_INDEX(t1) */ t1.version_id, 
       t1.id, 
       t2.field1, 
       t3.person_id, 
       t2.id 
  FROM table2 t2, 
       table3 t3,
       table1 t1 
 WHERE t1.id = t2.id + 0
   AND t1.version_id = t2.version_id + 0
   AND t2.id = 123
   AND t1.version_id = t3.version_id + 0
   AND t1.VERSION_NAME || '' <> 'AA' 
   AND t3.version_id = t2.version_id + 0
 order by t1.id
  • 计划费用:686
  • 经过时间:00:00:00.95
  • 记录数:40,717

问题:

  1. 为什么重新排列FROM子句中表格的顺序有帮助?

  2. 为什么在+ 0子句比较中添加WHERE有帮助?

  3. 为什么|| '' <> 'AA'子句WHERE比较中的VERSION_NAME有帮助?这是处理此列上可能nulls的更有效方法吗?

5 个答案:

答案 0 :(得分:2)

如果您通过解释计划运行这两个陈述,您将自己看到差异。为此,请发出:

explain plan
for
<your query>;

select * from table(dbms_xplan.display);

如果仍然不清楚为什么会出现这种差异,那么请在此处粘贴输出。

此致 罗布。

PS:“+ 0”和“||”'只是一些技巧,可以确保不使用列上的常规索引。它们也使您的查询不太可读,所以我会自己调整它们,而不是依赖于工具。

答案 1 :(得分:2)

首先要注意的是,“后”计划的成本低于“之前”计划。

这告诉我们第一个查询没有考虑为第二个查询选择的计划,因为Oracle会选择较低的成本计划。

添加USE_NL_WITH_INDEX提示不会影响任何计划的成本。它的作用是,如果一个带有索引计划的嵌套循环可用,那么即使Oracle是更有效的计划,任何其他计划也将被排除在考虑之外。

其次,“t1.id = t2.id”的谓词允许我们从t1开始并链接到t2或从t2开始并链接到t1。将该谓词更改为“t1.id = t2.id + 0”意味着它只能从t2(将0添加到id)链接到t1。 Oracle不够明白,它可以从t1开始(从id减去0)并加入到t2(或者添加/最小化0无关紧要)。

这些技巧都会阻止使用特定的访问路径。两者都不能说明所选计划的成本明显下降。

同时给出“AND t1.version_id = t2.version_id”和“AND t1.version_id = t3.version_id”,然后 “t3.version_id = t2.version_id”是给定的(受数据类型转换的影响)。但是,明确地添加它会向Oracle建议,由于正在应用额外条件,因此将返回更少的行,这可能会以更低的成本反映出来。

如果t2和t3 version_id不是数字,则可以解释成本的变化。 “+ 0”将强制进行数据类型转换,这可能允许使用索引。我认为这不太可能。

我怀疑原计划是从t1开始的(t1.id = 123和version_name&lt;&gt;'AA')。额外的谓词会(可能)迫使它从t2开始。

个人而言,我不喜欢任何其他优化。没有解决为什么最初选择了错误的计划。

答案 2 :(得分:1)

我同意彼得的评论 - 尝试从“改进的”查询中提取并查看它是否仍然表现良好。

如果oracle不想使用它,您可能需要更新此表的统计信息...

编辑:每个表中的version_id和id列是否都是相同的数据类型?

答案 3 :(得分:1)

补充问题汤姆提交的答案here is a link使用工具进行调整(或其他n步骤方法)。

答案 4 :(得分:0)

几乎可以肯定,这些表的统计数据是错误的,导致优化器选择一个糟糕的计划。

收集表和索引的统计信息(如果您无法控制此类事件,请将DBA收到),然后再次尝试查询。