4

我试图了解 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 行所示。

现在我在区域表的 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

3 回答 3

2

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

无索引:
“街在哪里?”

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

第二个问题提供了更大的上下文,因此您可以更快地推断出来,并且您不必枚举所有这些街道。

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

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

对于第三个问题,我想这是 Oracle 流程的一部分,并且没有记录供全世界使用。

第一个问题,不一定,都是以成本为基础的。

于 2013-03-22T17:15:01.907 回答
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 一次只能连接两个表(或行源)。一个join的结果也是可以join下一个表的row source
于 2013-03-22T22:46:06.113 回答
1

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

选择国家。* 从国家加入地区 (countries.region_id = region.region_id) where regions.region_name = 'Europe';

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

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

  1. 表上的统计
  2. 表列的统计信息
  3. 表列值的直方图
  4. 索引的存在
  5. 索引的大小、类型和统计信息——尤其是聚类因子
  6. 约束的存在——包括非空约束和检查约束。
  7. 每秒单块和多块读取和 cpu 操作的估计成本。
  8. 分区
  9. 物化视图和/或查询重写声明的存在和状态。
  10. 以前版本的查询的性能。

所以简而言之,不要对优化器所做的任何事情感到惊讶。这是一个非常复杂的套件。

于 2013-03-23T10:02:15.207 回答