Oracle" Total"计划成本确实低于其中的一些要素

时间:2014-08-07 10:09:43

标签: oracle query-performance

我无法弄清楚为什么有时候,计划的总成本可能只是一个非常小的数字,而在计划内部我们可以发现巨大的成本。 (实际上查询非常慢)。

有人可以解释一下吗?

这是一个例子。 显然,成本较高的部分来自主要选择中的一个字段,该字段在子视图上执行listagg,而具有此子视图的连接条件包含复杂条件(我们可以在一个字段或另一个字段上加入)。


| Id  | Operation                                    | Name                      | Rows  | Bytes | Cost  |
----------------------------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT                             |                           |     1 |   875 |    20 |
|   1 |  SORT GROUP BY                               |                           |     1 |   544 |       |
|   2 |   VIEW                                       |                           |     1 |   544 |     3 |
|   3 |    SORT UNIQUE                               |                           |     1 |   481 |     3 |
|   4 |     NESTED LOOPS                             |                           |       |       |       |
|   5 |      NESTED LOOPS                            |                           |     3 |  1443 |     2 |
|   6 |       TABLE ACCESS BY INDEX ROWID            |                           |     7 |   140 |     1 |
|   7 |        INDEX RANGE SCAN                      |                           |     7 |       |     1 |
|   8 |       INDEX UNIQUE SCAN                      |                           |     1 |       |     1 |
|   9 |      TABLE ACCESS BY INDEX ROWID             |                           |     1 |   461 |     1 |
|  10 |  SORT GROUP BY                               |                           |     1 |   182 |       |
|  11 |   NESTED LOOPS                               |                           |       |       |       |
|  12 |    NESTED LOOPS                              |                           |     8 |  1456 |     3 |
|  13 |     NESTED LOOPS                             |                           |     8 |   304 |     2 |
|  14 |      TABLE ACCESS BY INDEX ROWID             |                           |     7 |   154 |     1 |
|  15 |       INDEX RANGE SCAN                       |                           |     7 |       |     1 |
|  16 |      INDEX RANGE SCAN                        |                           |     1 |    16 |     1 |
|  17 |     INDEX RANGE SCAN                         |                           |     1 |       |     1 |
|  18 |    TABLE ACCESS BY INDEX ROWID               |                           |     1 |   144 |     1 |
|  19 |  SORT GROUP BY                               |                           |     1 |   268 |       |
|  20 |   VIEW                                       |                           |     1 |   268 |     9 |
|  21 |    SORT UNIQUE                               |                           |     1 |   108 |     9 |
|  22 |     CONCATENATION                            |                           |       |       |       |
|  23 |      NESTED LOOPS                            |                           |       |       |       |
|  24 |       NESTED LOOPS                           |                           |     1 |   108 |     4 |
|  25 |        NESTED LOOPS                          |                           |     1 |    79 |     3 |
|  26 |         NESTED LOOPS                         |                           |     1 |    59 |     2 |
|  27 |          TABLE ACCESS BY INDEX ROWID         |                           |     1 |    16 |     1 |
|  28 |           INDEX UNIQUE SCAN                  |                           |     1 |       |     1 |
|  29 |          TABLE ACCESS BY INDEX ROWID         |                           |     1 |    43 |     1 |
|  30 |           INDEX RANGE SCAN                   |                           |     1 |       |     1 |
|  31 |         TABLE ACCESS BY INDEX ROWID          |                           |     1 |    20 |     1 |
|  32 |          INDEX UNIQUE SCAN                   |                           |     1 |       |     1 |
|  33 |        INDEX UNIQUE SCAN                     |                           |     1 |       |     1 |
|  34 |       TABLE ACCESS BY INDEX ROWID            |                           |     1 |    29 |     1 |
|  35 |      NESTED LOOPS                            |                           |       |       |       |
|  36 |       NESTED LOOPS                           |                           |     1 |   108 |     4 |
|  37 |        NESTED LOOPS                          |                           |     1 |    79 |     3 |
|  38 |         NESTED LOOPS                         |                           |     1 |    59 |     2 |
|  39 |          TABLE ACCESS BY INDEX ROWID         |                           |     4 |    64 |     1 |
|  40 |           INDEX RANGE SCAN                   |                           |     2 |       |     1 |
|  41 |          TABLE ACCESS BY INDEX ROWID         |                           |     1 |    43 |     1 |
|  42 |           INDEX RANGE SCAN                   |                           |     1 |       |     1 |
|  43 |         TABLE ACCESS BY INDEX ROWID          |                           |     1 |    20 |     1 |
|  44 |          INDEX UNIQUE SCAN                   |                           |     1 |       |     1 |
|  45 |        INDEX UNIQUE SCAN                     |                           |     1 |       |     1 |
|  46 |       TABLE ACCESS BY INDEX ROWID            |                           |     1 |    29 |     1 |
|  47 |  SORT GROUP BY                               |                           |     1 |   330 |       |
|  48 |   VIEW                                       |                           |     1 |   330 | 26695 |
|  49 |    SORT UNIQUE                               |                           |     1 |   130 | 26695 |
|  50 |     CONCATENATION                            |                           |       |       |       |
|  51 |      HASH JOIN ANTI                          |                           |     1 |   130 | 13347 |
|  52 |       NESTED LOOPS                           |                           |       |       |       |
|  53 |        NESTED LOOPS                          |                           |     1 |   110 |     4 |
|  54 |         NESTED LOOPS                         |                           |     1 |    81 |     3 |
|  55 |          NESTED LOOPS                        |                           |     1 |    61 |     2 |
|  56 |           TABLE ACCESS BY INDEX ROWID        |                           |     1 |    16 |     1 |
|  57 |            INDEX UNIQUE SCAN                 |                           |     1 |       |     1 |
|  58 |           TABLE ACCESS BY INDEX ROWID        |                           |     1 |    45 |     1 |
|  59 |            INDEX RANGE SCAN                  |                           |     1 |       |     1 |
|  60 |          TABLE ACCESS BY INDEX ROWID         |                           |     1 |    20 |     1 |
|  61 |           INDEX UNIQUE SCAN                  |                           |     1 |       |     1 |
|  62 |         INDEX UNIQUE SCAN                    |                           |     1 |       |     1 |
|  63 |        TABLE ACCESS BY INDEX ROWID           |                           |     1 |    29 |     1 |
|  64 |       VIEW                                   |                           |   164K|  3220K| 13341 |
|  65 |        NESTED LOOPS                          |                           |       |       |       |
|  66 |         NESTED LOOPS                         |                           |   164K|    11M| 13341 |
|  67 |          NESTED LOOPS                        |                           |   164K|  8535K| 10041 |
|  68 |           TABLE ACCESS BY INDEX ROWID        |                           |   164K|  6924K|  8391 |
|  69 |            INDEX SKIP SCAN                   |                           |  2131K|       |   163 |
|  70 |           INDEX UNIQUE SCAN                  |                           |     1 |    10 |     1 |
|  71 |          INDEX UNIQUE SCAN                   |                           |     1 |       |     1 |
|  72 |         TABLE ACCESS BY INDEX ROWID          |                           |     1 |    20 |     1 |
|  73 |      HASH JOIN ANTI                          |                           |     2 |   260 | 13347 |
|  74 |       NESTED LOOPS                           |                           |       |       |       |
|  75 |        NESTED LOOPS                          |                           |     2 |   220 |     4 |
|  76 |         NESTED LOOPS                         |                           |     2 |   162 |     3 |
|  77 |          NESTED LOOPS                        |                           |     2 |   122 |     2 |
|  78 |           TABLE ACCESS BY INDEX ROWID        |                           |     4 |    64 |     1 |
|  79 |            INDEX RANGE SCAN                  |                           |     2 |       |     1 |
|  80 |           TABLE ACCESS BY INDEX ROWID        |                           |     1 |    45 |     1 |
|  81 |            INDEX RANGE SCAN                  |                           |     1 |       |     1 |
|  82 |          TABLE ACCESS BY INDEX ROWID         |                           |     1 |    20 |     1 |
|  83 |           INDEX UNIQUE SCAN                  |                           |     1 |       |     1 |
|  84 |         INDEX UNIQUE SCAN                    |                           |     1 |       |     1 |
|  85 |        TABLE ACCESS BY INDEX ROWID           |                           |     1 |    29 |     1 |
|  86 |       VIEW                                   |                           |   164K|  3220K| 13341 |
|  87 |        NESTED LOOPS                          |                           |       |       |       |
|  88 |         NESTED LOOPS                         |                           |   164K|    11M| 13341 |
|  89 |          NESTED LOOPS                        |                           |   164K|  8535K| 10041 |
|  90 |           TABLE ACCESS BY INDEX ROWID        |                           |   164K|  6924K|  8391 |
|  91 |            INDEX SKIP SCAN                   |                           |  2131K|       |   163 |
|  92 |           INDEX UNIQUE SCAN                  |                           |     1 |    10 |     1 |
|  93 |          INDEX UNIQUE SCAN                   |                           |     1 |       |     1 |
|  94 |         TABLE ACCESS BY INDEX ROWID          |                           |     1 |    20 |     1 |
|  95 |  NESTED LOOPS OUTER                          |                           |     1 |   875 |    20 |
|  96 |   NESTED LOOPS OUTER                         |                           |     1 |   846 |    19 |
|  97 |    NESTED LOOPS OUTER                        |                           |     1 |   800 |    18 |
|  98 |     NESTED LOOPS OUTER                       |                           |     1 |   776 |    17 |
|  99 |      NESTED LOOPS OUTER                      |                           |     1 |   752 |    16 |
| 100 |       NESTED LOOPS OUTER                     |                           |     1 |   641 |    15 |
| 101 |        NESTED LOOPS OUTER                    |                           |     1 |   576 |    14 |
| 102 |         NESTED LOOPS OUTER                   |                           |     1 |   554 |    13 |
| 103 |          NESTED LOOPS OUTER                  |                           |     1 |   487 |    12 |
| 104 |           NESTED LOOPS OUTER                 |                           |     1 |   434 |    11 |
| 105 |            NESTED LOOPS                      |                           |     1 |   368 |    10 |
| 106 |             NESTED LOOPS                     |                           |     1 |   102 |     9 |
| 107 |              NESTED LOOPS OUTER              |                           |     1 |    85 |     8 |
| 108 |               NESTED LOOPS                   |                           |     1 |    68 |     7 |
| 109 |                NESTED LOOPS                  |                           |    50 |  2700 |     6 |
| 110 |                 HASH JOIN                    |                           |    53 |  1696 |     5 |
| 111 |                  INLIST ITERATOR             |                           |       |       |       |
| 112 |                   TABLE ACCESS BY INDEX ROWID|                           |   520 | 10400 |     3 |
| 113 |                    INDEX RANGE SCAN          |                           |   520 |       |     1 |
| 114 |                  INLIST ITERATOR             |                           |       |       |       |
| 115 |                   TABLE ACCESS BY INDEX ROWID|                           | 91457 |  1071K|     1 |
| 116 |                    INDEX UNIQUE SCAN         |                           |     2 |       |     1 |
| 117 |                 TABLE ACCESS BY INDEX ROWID  |                           |     1 |    22 |     1 |
| 118 |                  INDEX UNIQUE SCAN           |                           |     1 |       |     1 |
| 119 |                TABLE ACCESS BY INDEX ROWID   |                           |     1 |    14 |     1 |
| 120 |                 INDEX UNIQUE SCAN            |                           |     1 |       |     1 |
| 121 |               TABLE ACCESS BY INDEX ROWID    |                           |     1 |    17 |     1 |
| 122 |                INDEX UNIQUE SCAN             |                           |     1 |       |     1 |
| 123 |              TABLE ACCESS BY INDEX ROWID     |                           |     1 |    17 |     1 |
| 124 |               INDEX UNIQUE SCAN              |                           |     1 |       |     1 |
| 125 |             TABLE ACCESS BY INDEX ROWID      |                           |     1 |   266 |     1 |
| 126 |              INDEX UNIQUE SCAN               |                           |     1 |       |     1 |
| 127 |            TABLE ACCESS BY INDEX ROWID       |                           |     1 |    66 |     1 |
| 128 |             INDEX UNIQUE SCAN                |                           |     1 |       |     1 |
| 129 |           TABLE ACCESS BY INDEX ROWID        |                           |     1 |    53 |     1 |
| 130 |            INDEX UNIQUE SCAN                 |                           |     1 |       |     1 |
| 131 |          TABLE ACCESS BY INDEX ROWID         |                           |     1 |    67 |     1 |
| 132 |           INDEX UNIQUE SCAN                  |                           |     1 |       |     1 |
| 133 |         INDEX RANGE SCAN                     |                           |     1 |    22 |     1 |
| 134 |        TABLE ACCESS BY INDEX ROWID           |                           |     1 |    65 |     1 |
| 135 |         INDEX UNIQUE SCAN                    |                           |     1 |       |     1 |
| 136 |       TABLE ACCESS BY INDEX ROWID            |                           |     1 |   111 |     1 |
| 137 |        INDEX UNIQUE SCAN                     |                           |     1 |       |     1 |
| 138 |      TABLE ACCESS BY INDEX ROWID             |                           |     1 |    24 |     1 |
| 139 |       INDEX UNIQUE SCAN                      |                           |     1 |       |     1 |
| 140 |     TABLE ACCESS BY INDEX ROWID              |                           |     1 |    24 |     1 |
| 141 |      INDEX UNIQUE SCAN                       |                           |     1 |       |     1 |
| 142 |    TABLE ACCESS BY INDEX ROWID               |                           |     1 |    46 |     1 |
| 143 |     INDEX UNIQUE SCAN                        |                           |     1 |       |     1 |
| 144 |   TABLE ACCESS BY INDEX ROWID                |                           |     1 |    29 |     1 |
| 145 |    INDEX UNIQUE SCAN                         |                           |     1 |       |     1 |
----------------------------------------------------------------------------------------------------------

1 个答案:

答案 0 :(得分:3)

声明的总成本通常等于或大于其任何子操作的成本。此规则至少有4个例外。

您的计划看起来像#3,但我们无法查看代码。

<强> 1。 FILTER

执行计划可能取决于运行时的条件。这些条件导致FILTER操作将动态决定执行哪个查询块。下面的示例使用静态条件,但仍然演示了这个概念。子查询的一部分是非常昂贵的,但条件否定了整个事情。

explain plan for select * from dba_objects cross join dba_objects where 1 = 2;
select * from table(dbms_xplan.display(format => 'basic +cost'));

Plan hash value: 3258663795

--------------------------------------------------------------------
| Id  | Operation                       | Name        | Cost (%CPU)|
--------------------------------------------------------------------
|   0 | SELECT STATEMENT                |             |     0   (0)|
|   1 |  FILTER                         |             |            |
|   2 |   MERGE JOIN CARTESIAN          |             |    11M  (3)|
...

<强> 2。 COUNT STOPKEY

执行计划将子操作汇总到最终成本。但是儿童行动并不总能完成。在下面的示例中,可能正确的说计划的一部分成本为214.但由于条件where rownum <= 1,只有部分子操作可能会运行。

explain plan for
select /*+ no_query_transformation */ *
from (select * from dba_objects join dba_objects using (owner))
where rownum <= 1;

select * from table(dbms_xplan.display(format => 'basic +cost'));

Plan hash value: 2132093199

-------------------------------------------------------------------------------
| Id  | Operation                         | Name                 | Cost (%CPU)|
-------------------------------------------------------------------------------
|   0 | SELECT STATEMENT                  |                      |     4   (0)|
|   1 |  COUNT STOPKEY                    |                      |            |
|   2 |   VIEW                            |                      |     4   (0)|
|   3 |    VIEW                           |                      |     4   (0)|
|   4 |     NESTED LOOPS                  |                      |     4   (0)|
|   5 |      VIEW                         | DBA_OBJECTS          |     2   (0)|
|   6 |       UNION-ALL                   |                      |            |
|   7 |        HASH JOIN                  |                      |     3  (34)|
|   8 |         INDEX FULL SCAN           | I_USER2              |     1   (0)|
|   9 |         VIEW                      | _CURRENT_EDITION_OBJ |     1   (0)|
|  10 |          FILTER                   |                      |            |
|  11 |           HASH JOIN               |                      |   214   (3)|
...

第3。 SELECT列列表中的子查询

成本聚合不包括SELECT列列表中的子查询。像select ([expensive query]) from dual;这样的查询总费用非常低。我不明白这个的原因; Oracle估计子查询和FROM中的行数,当然它可以将它们相乘以获得总成本。

explain plan for
select dummy,(select count(*) from dba_objects cross join dba_objects) from dual;
select * from table(dbms_xplan.display(format => 'basic +cost'));

Plan hash value: 3705842531

---------------------------------------------------------------
| Id  | Operation                  | Name        | Cost (%CPU)|
---------------------------------------------------------------
|   0 | SELECT STATEMENT           |             |     2   (0)|
|   1 |  SORT AGGREGATE            |             |            |
|   2 |   MERGE JOIN CARTESIAN     |             |    11M  (3)|
...

<强> 4。其他 - 四舍五入?错误?

大约0.01%的计划仍然存在无法解释的成本问题。我找不到他们中的任何模式。也许它只是一个舍入问题或一些罕见的优化器错误。总会有一些奇怪的情况,任何模型都像优化器一样复杂。

检查更多例外情况

此查询可以找到其他例外,它会返回第一个成本低于最高成本的所有计划。

select *
from
(
  --First and Max cost per plan.
  select
    sql_id, plan_hash_value, id, cost
    ,max(cost) keep (dense_rank first order by id)
      over (partition by sql_id, plan_hash_value) first_cost
    ,max(cost)
      over (partition by sql_id, plan_hash_value) max_cost
    ,max(case when operation = 'COUNT' and options = 'STOPKEY' then 1 else 0 end)
      over (partition by sql_id, plan_hash_value) has_count_stopkey
    ,max(case when operation = 'FILTER' and options is null then 1 else 0 end)
      over (partition by sql_id, plan_hash_value) has_filter
    ,count(distinct(plan_hash_value))
      over () total_plans
  from v$sql_plan
  --where sql_id = '61a161nm1ttjj'
  order by 1,2,3
)
where first_cost < max_cost
  --It's easy to exclude FILTER and COUNT STOPKEY.
  and has_filter = 0
  and has_count_stopkey = 0
order by 1,2,3;