COUNT()的影响基于表中的列

时间:2014-01-29 17:09:47

标签: sql performance oracle oracle11g exadata

修改:

  

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


为过去的问题制定问题调查报告,我对下面的情况略感混淆。

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

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

COL2 VARCHAR2(9))还有另一个唯一索引。这是App经常使用的。什么曾经更新我的意思以前基于这两列发生。鉴于此表上仅对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秒!

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

查询1 :(使用主键)

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
  

我们可以在CostTime条件下找到没有主要内容的查询   关键胜利。那么主键的执行时间如何呢?   更快???

编辑:

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

3 个答案:

答案 0 :(得分:4)

您从PK索引中读取的数据多于从另一个中读取的数据。 COL1VARCHAR2(18)COL2VARCHAR(9),这并不一定意味着任何事情,但暗示您COL1中的值可能始终长于COL2中的值VARCHAR2。因此,它们将在表和索引中使用更多存储,并且索引扫描必须从块缓冲区和/或磁盘中提取更多数据以用于基于PK的查询。

执行统计数据显示;对于基于PK的查询,41332是一致的获取,对于更快的查询,只有28151,所以它在PK上做了更多的工作。分段大小也显示出来 - 对于PK,你需要读取大约328M,而英国只需要224M。

如果您看到PK版本有时运行得更快,则块缓冲区可能至关重要。在这个例子中,你已经证明这两个查询均创下块缓冲区 - 23物理读是一个微不足道的数字,如果索引数据不一致的缓存,那么你可能会看到41K一致获取与28K物理读取,这将可能逆转从磁盘进行物理读取的明显优胜者将会变慢。如果反向运行两个查询会更快地显示一个查询,但通常会反映出他们运行的顺序会显示另一个查询更快。

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

答案 1 :(得分:1)

给出类似

的陈述
select count(x) from some_table

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

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

这可以产生很大的不同。如果索引是聚簇的,则作为索引的B树中的叶节点是表的数据页。考虑到你的行有多大(或似乎是),这意味着对聚簇索引的扫描可能会移动更多的数据 - 意味着更多的分页 - 而不是扫描非聚集索引。 / p>

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

select count(*) from myacct

select count(1) from myacct

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

只是一个想法。

[1]我认为它们是各自索引中的唯一列。

答案 2 :(得分:0)

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