2

编辑:

数据库 - Oracle 11gR2 - 通过 Exadata (X2)


我正在为过去的问题编写问题调查报告,我对以下情况有些困惑。

说,我有一张桌子MYACCT。有138列。它保存着10 Million记录。每小时至少定期更新 1000 条记录(插入/更新/删除)。

主键是COL1 (VARCHAR2(18))(应用程序很少使用这个,除了与其他表的连接)

有另一个唯一索引COL2 VARCHAR2(9))。这是一个应用程序经常使用。我之前所说的任何更新都是基于这两列发生的。鉴于SELECT此表的任何唯一操作,请始终参考COL2. 我们COL2的兴趣也是如此。

我们在下面做一个查询,

SELECT COUNT(COL2) FROM MYACCT; /* Use the Unique Column (Not PK) */

结果没有问题,而我是建议将其更改为的人

SELECT COUNT(COL1) FROM MYACCT; /* Use the primary Index

我只是计算了实际执行所需的时间

使用 PRIMARY KEY 查询总是快 0.8-1.0 秒!

现在,我试图解释这种行为。只是起草这些查询背后的解释计划。

查询一:(使用主键)

SELECT COUNT(COL1) FROM MYACCT;

计划 :

SQL> select * from TABLE(dbms_xplan.display);
Plan hash value: 2417095184

---------------------------------------------------------------------------------
| Id  | Operation                     | Name    | Rows  | Cost (%CPU)| Time     |
---------------------------------------------------------------------------------
|   0 | SELECT STATEMENT              |         |     1 | 11337   (1)| 00:02:17 |
|   1 |  SORT AGGREGATE               |         |     1 |            |          |
|   2 |   INDEX STORAGE FAST FULL SCAN| PK_ACCT |    10M| 11337   (1)| 00:02:17 |
---------------------------------------------------------------------------------

9 rows selected.

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

查询2:(不使用主键)

SELECT COUNT(COL2) FROM MYACCT;

计划 :

Plan hash value: 1130703739

------------------------------------------------------------------------------------------
| Id  | Operation                     | Name     | Rows  | Bytes | Cost (%CPU)| Time     |
------------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT              |          |     1 |    10 |  7868   (1)| 00:01:35 |
|   1 |  SORT AGGREGATE               |          |     1 |    10 |            |          |
|   2 |   INDEX STORAGE FAST FULL SCAN| MYINDX01 |    10M|    95M|  7868   (1)| 00:01:35 |
------------------------------------------------------------------------------------------

9 rows selected.

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

我们可以发现,Cost没有Time主键的查询获胜。那为什么主键的执行时间更快???

编辑:

SQL> select segment_name, bytes from dba_segments where segment_name in ('MYINDX01','PK_ACCT');
PK_ACCT               343932928
MYINDX01              234881024
4

3 回答 3

4

您从 PK 索引中读取的数据比从另一个索引中读取的数据多。COL1is VARCHAR2(18)while COL2is VARCHAR(9),这并不一定意味着什么,但意味着您可能具有COL1始终比COL2. 因此,它们将在表和索引中使用更多存储空间,并且索引扫描必须从块缓冲区和/或磁盘中提取更多数据以进行基于 PK 的查询。

执行统计表明;41332 一致的获取用于基于 PK 的查询,只有 28151 用于更快的查询,因此它在 PK 上做更多的工作。分段大小也显示了这一点——对于 PK,您需要阅读大约 328M,而对于英国,只有 224M。

如果您看到 PK 版本有时运行得更快,那么块缓冲区可能至关重要。在示例中,您已显示两个查询都在访问块缓冲区 - 23 次物理读取是一个微不足道的数字,如果索引数据未一致缓存,那么您可能会看到 41k 一致获取与 28k 物理读取,这可能会反转明显的赢家,因为从磁盘进行物理读取会更慢。如果背靠背运行两个查询显示一个更快,但颠倒它们运行的​​顺序会显示另一个更快,这通常会体现出来。

您不能将此概括为“PK 查询比英国查询慢”;这是因为您的特定数据。如果您的 PK 实际上是一个数字列,而不是一个包含数字的列,那么您可能还会获得更好的性能VARCHAR2,这绝不是一个好主意。

于 2014-01-29T17:36:15.367 回答
1

给出这样的声明

select count(x) from some_table

如果column有覆盖索引x,则查询优化器很可能会使用它,因此它不必获取 [巨大] 数据页。

听起来您的类似查询中涉及的两列(col1和)都已编入索引[1]。col2您没有说的是这些索引中的任何一个是否是clustered

这可以产生很大的不同。如果索引是聚簇的,那么作为索引的 B 树中的叶节点就是表的数据页。鉴于您的行有多大(或看起来有多大),这意味着与扫描非聚集索引相比,对聚集索引的扫描可能会移动更多的数据——这意味着更多的分页。

大多数聚合函数在计算聚合函数的值时会消除空值。count()有点不同。count(*)在结果中包括空值,而count(expression)从结果中排除空值。由于您没有使用distinct,并假设您的col1col2列是not null,您可能会通过尝试获得更好的性能

select count(*) from myacct

或者

select count(1) from myacct

因此优化器不必考虑该列是否为空。

只是一个想法。

[1]并且我假设它们是各自索引中的唯一列。

于 2014-01-29T23:51:40.803 回答
0

您的 PK 查询正在进行 0 次物理读取,这表明您在内存中有结果。因此,即使执行计划看起来更慢,它的执行速度也更快。COL2 查询正在执行 23 次物理读取。

于 2014-01-29T17:44:48.850 回答