Oracle SQL查询 - 意外的查询计划

时间:2010-03-10 14:33:56

标签: sql plsql oracle10g sql-execution-plan

我有一个非常简单的查询,它给了我意想不到的结果。关于在何处进行故障排除的提示将受到欢迎。

简化,查询是:

SELECT Obs.obsDate, 
       Obs.obsValue, 
       ObsHead.name
  FROM ml.Obs Obs 
  JOIN ml.ObsHead ObsHead ON ObsHead.hdId = Obs.hdId
 WHERE obs.hdId IN (53, 54)

这给我的查询费用为: 963 。但是,如果我将查询更改为:

SELECT Obs.obsDate, 
       Obs.obsValue, 
       ObsHead.name
  FROM ml.Obs Obs 
  JOIN ml.ObsHead ObsHead ON ObsHead.hdId = Obs.hdId
 WHERE ObsHead.name IN ('BP SYSTOLIC', 'BP DIASTOLIC')

虽然它(应该)返回相同的数据,但估计成本最高可达 17688 。这里的问题可能在哪里?感谢。

编辑:查询计划表明ObsHead.Name上的索引用于范围扫描,而ObsHead上的表访问仅花费4. {{1}上有另一个索引用于范围扫描的成本为94:它是表之间的嵌套循环连接,跳转到17K。

4 个答案:

答案 0 :(得分:1)

hdId上可能有一个索引(如果它是主键,我怀疑是这种情况),而不是name,这意味着第二个查询必须执行全表扫描。

答案 1 :(得分:1)

成本仅用于比较一个查询的不同计划;它们对于比较不同的查询并不是那么有用。

您需要查看计划并根据其执行的操作进行比较。

我怀疑这些查询的实际性能是相似的 - 但是知道第一个查询是否使用散列连接会很有趣,如果obs中匹配的记录百分比是显著。

答案 2 :(得分:1)

我发现优化器提供的成本很有意思,但并不是特别有用。我发现比较查询的最好方法是运行它们并查看它们相对于彼此的表现。

分享并享受。

答案 3 :(得分:1)

如前所述,该计划的成本并非用于比较两个不同的查询,仅用于比较同一查询的不同路径。

这只是猜测,但在这种情况下,计划的基数字段可能对您更有用。如果OBSHEAD上的索引不是唯一的并且使用估计收集了统计信息,那么优化器可能无法确切地知道查询该表时要预期的行数。基数会告诉你这是否真实(理想情况下,你会看到OBSHEAD的基数为2)。

另一个建议是检查OBS的统计数据。似乎这是一个经常增长的表,在这种情况下,1月28日不足以收集统计数据。假设为此表启用了监视,下面的查询可以告诉您统计信息是否陈旧且需要刷新。

select owner, table_name, last_analyzed, stale_stats
from all_tab_statistics
where owner = 'ML' and table_name = 'OBS';

select owner, index_name, last_analyzed, stale_stats
from all_ind_statistics
where owner = 'ML' and table_name = 'OBS';