自动跟踪统计比较

Auto trace statistics comparison

比较生成相同行数的不同查询时,如何判断哪个 oracle 计划好?

如果我不得不认为last_consistent_gets低,我看到经过的时间更多。 对于其他查询,经过的时间更少,但 last_consistent_gets 更多。

非常混乱。

运行时间通常是 Oracle 性能最重要的指标。理论上,我们有时可能想牺牲一个 SQL 语句的 运行 时间来为其他语句保留资源。实际上,这种情况很少见。

在您的特定情况下,很多时候使用更一致获取的语句既更快又更高效。例如,当从 table 中检索大部分数据时,完整 table 扫描通常比索引扫描更有效。完整的 table 扫描可以使用 multi-block 读取,这比索引扫描的多次 single-block 读取效率更高。存储系统读取大块数据的速度通常比读取多个小块数据快得多。

下面的示例比较了从 table 读取 25% 的数据。索引方法只使用了一半的一致性获取,但它的速度也是两倍多。

示例架构

创建一个简单的 table 并编制索引并收集统计信息。

create table test1(a number, b number);
insert into test1 select level, level from dual connect by level <= 1000000;
create index test1_ids on test1(a);
begin
    dbms_stats.gather_table_stats(user, 'TEST1');
end;
/

自动追踪

下面的代码显示了完整的 table 扫描消耗了 2082 次一致获取,强制索引访问消耗了 1078 次一致获取。

JHELLER@orclpdb> set autotrace on;
JHELLER@orclpdb> set linesize 120;
JHELLER@orclpdb> select sum(b) from test1 where a >= 750000;

    SUM(B)
----------
2.1875E+11


Execution Plan
----------------------------------------------------------
Plan hash value: 3896847026

----------------------------------------------------------------------------
| Id  | Operation          | Name  | Rows  | Bytes | Cost (%CPU)| Time     |
----------------------------------------------------------------------------
|   0 | SELECT STATEMENT   |       |     1 |    10 |   597   (3)| 00:00:01 |
|   1 |  SORT AGGREGATE    |       |     1 |    10 |            |          |
|*  2 |   TABLE ACCESS FULL| TEST1 |   250K|  2441K|   597   (3)| 00:00:01 |
----------------------------------------------------------------------------

Predicate Information (identified by operation id):
---------------------------------------------------

   2 - filter("A">=750000)


Statistics
----------------------------------------------------------
          0  recursive calls
          0  db block gets
       2082  consistent gets
          0  physical reads
          0  redo size
        552  bytes sent via SQL*Net to client
        404  bytes received via SQL*Net from client
          2  SQL*Net roundtrips to/from client
          0  sorts (memory)
          0  sorts (disk)
          1  rows processed

JHELLER@orclpdb> select /*+ index(test1) */ sum(b) from test1 where a >= 750000;

    SUM(B)
----------
2.1875E+11


Execution Plan
----------------------------------------------------------
Plan hash value: 1247966541

--------------------------------------------------------------------------------------------------
| Id  | Operation                            | Name      | Rows  | Bytes | Cost (%CPU)| Time     |
--------------------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT                     |           |     1 |    10 |  1084   (1)| 00:00:01 |
|   1 |  SORT AGGREGATE                      |           |     1 |    10 |            |          |
|   2 |   TABLE ACCESS BY INDEX ROWID BATCHED| TEST1     |   250K|  2441K|  1084   (1)| 00:00:01 |
|*  3 |    INDEX RANGE SCAN                  | TEST1_IDS |   250K|       |   563   (1)| 00:00:01 |
--------------------------------------------------------------------------------------------------

Predicate Information (identified by operation id):
---------------------------------------------------

   3 - access("A">=750000)


Statistics
----------------------------------------------------------
          0  recursive calls
          0  db block gets
       1078  consistent gets
          0  physical reads
          0  redo size
        552  bytes sent via SQL*Net to client
        424  bytes received via SQL*Net from client
          2  SQL*Net roundtrips to/from client
          0  sorts (memory)
          0  sorts (disk)
          1  rows processed

性能

如果你 运行 循环语句一百次(并且 运行 那些循环多次以忽略缓存和其他系统 activity),完整的 table 扫描版本 运行s 比强制索引扫描版本快得多。

--Seconds to run plan with more consistent gets: 1.7, 1.7, 1.8
declare
    v_count number;
begin
    for i in 1 .. 100 loop
        select sum(b) into v_count from test1 where a >= 750000;
    end loop;
end;
/


--Seconds to run plan with less consistent gets: 4.5, 4,5, 4.5
declare
    v_count number;
begin
    for i in 1 .. 100 loop
        select /*+ index(test1) */ sum(b) into v_count from test1 where a >= 750000;
    end loop;
end;
/

例外情况

有些时候资源消耗比流逝的时间更重要。例如,并行性是一种欺骗,因为它迫使系统更努力地工作,而不是更聪明地工作。单个 out-of-control 并行查询可以关闭整个系统。有时您需要将语句分解为效率较低的版本,以减少锁定某些内容的时间,或者避免消耗过多的 UNDO 或临时 table 空间。

但上面的例子是有些不常见的例外,它们通常只发生在处理查询大量数据的数据仓库时。对于大多数 OLTP 系统,每个查询都不到一秒,经过的时间是您唯一需要担心的指标。