了解oracle中的解释计划

时间:2013-03-22 17:10:17

标签: oracle sql-execution-plan

我试图了解oracle中的解释计划,并想知道oracle在制定解释计划时考虑的条件

我正在测试oracle 11g中存在的HR模式中的简单查询

select * from countries 
where region_id in (select region_id from regions where region_name = 'Europe');

当我运行以下查询时:

explain plan for 
select * from countries 
where region_id in (select region_id from regions where region_name = 'Europe');

SELECT * FROM table(dbms_xplan.display(null,null,'basic'));

我在解释表中得到以下输出:

--------------------------------------------------------
| Id  | Operation                    | Name            |
--------------------------------------------------------
|   0 | SELECT STATEMENT             |                 |
|   1 |  NESTED LOOPS                |                 |
|   2 |   INDEX FULL SCAN            | COUNTRY_C_ID_PK |
|   3 |   TABLE ACCESS BY INDEX ROWID| REGIONS         |
|   4 |    INDEX UNIQUE SCAN         | REG_ID_PK       |
--------------------------------------------------------

在这里,我观察到外部查询首先被执行,即第一行执行了国家表,如第3行所示。

现在我在regions表的region_name上添加了一个索引,并再次运行了解释计划 并得到以下输出

--------------------------------------------------------------
| Id  | Operation                    | Name                  |
--------------------------------------------------------------
|   0 | SELECT STATEMENT             |                       |
|   1 |  NESTED LOOPS                |                       |
|   2 |   TABLE ACCESS BY INDEX ROWID| REGIONS               |
|   3 |    INDEX RANGE SCAN          | REGIONNAME_REGIONS_IX |
|   4 |   INDEX UNIQUE SCAN          | COUNTRY_C_ID_PK       |
|   5 |    INDEX RANGE SCAN          | COUNTRIES_REGIONID_IX |
--------------------------------------------------------------

现在我的问题是:

  1. 不管是否存在索引,都不应该首先执行内部查询
  2. 如果添加索引会改变执行计划,还有哪些其他功能可以改变它?
  3. 在一般情况下,执行过程是什么样的顺序(首先执行首先出现的连​​接然后转到查询中的下一个连接)?
  4. 提前感谢您的帮助。

    -Varun

3 个答案:

答案 0 :(得分:2)

解释计划在很大程度上依赖于基于成本的优化器(CBO)。您可以通过收集要查询的表的统计信息来帮助完成此过程。现在就索引为什么会改变计划而言,这是因为你已经向CBO提供了之前没有的关键信息。这相当于我问你这个问题:

无索引:
“街道在哪里?”

索引:
“那里有蓝色房子的街道在哪里?”

第二个问题提供了更大的背景,因此你可以更快地演绎,而且你不必枚举所有这些街道上的东西。

您可以向查询提供提示,即:

select /*+ parallel */ * from table
提供提示以并行运行此查询。

对于第三个问题,我认为这是一个Oracle流程,并没有记录供全世界使用。

在第一个问题中,并非必然,它都是基于成本的。

答案 1 :(得分:1)

我不知道他们是否在11g的执行计划输出中有任何改变,但你确定你向我们展示了正确的查询吗?您正在从表国家/地区中选择所有列(select *),但解释计划未显示任何表格访问权限?或者COUNTRY_C_ID_PK是否包含所有列?

我希望以下计划(没有索引):

SELECT
  NESTED LOOP
    FULL TABLE SCAN (regions)
    TABLE ACCESS BY INDEX ROWID (countries)
      INDEX RANGE SCAN (COUNTRIES_REGIONID_IX)

随着索引的到位,我希望会有这样的事情:

SELECT
  NESTED LOOP
    TABLE ACCESS BY INDEX ROWID (regions)
      INDEX RANGE SCAN (REGIONNAME_REGIONS_IX)
    TABLE ACCESS BY INDEX ROWID (countries)
      INDEX RANGE SCAN (COUNTRIES_REGIONID_IX)

对于你的问题:

  1. 根据可用的统计信息,Oracle可以根据内部或外部查询驱动查询,这取决于可用的统计信息
  2. 影响执行计划的事情很多......
  3. Oracle一次只能连接两个表(或行源)。连接的结果也是可以连接到下一个表的行源

答案 2 :(得分:1)

基于成本的优化工具经历了几个阶段,包括查询转换。您的查询几乎肯定会被优化器重写为:

选择国家。*    来自各国加入地区(countries.region_id = regions.region_id)    regions.region_name ='Europe';

因此,原始查询中表示的内部和外部查询的概念可能不适用于转换后。顺便说一句,这就是为什么有关EXISTS()和IN()的论点经常没有实际意义 - 两种情况下的查询通常都可以重写为连接。

优化程序使用的信息(取决于版本)包括:

  1. 表格统计
  2. 表格列的统计信息
  3. 表格列值的直方图
  4. 索引的存在
  5. 索引的大小和类型以及统计信息 - 特别是聚类因子
  6. 存在约束 - 包括非null和检查约束。
  7. 每秒单个和多个块读取和cpu操作的估计成本。
  8. 分区
  9. 物化视图和/或查询重写声明的存在和状态。
  10. 以前版本的查询的效果。
  11. 简而言之,不要对优化者做的任何事情感到惊讶。这是一个非常复杂的工具包。