Oracle和group by的奇怪行为

时间:2019-09-22 12:02:22

标签: sql oracle oracle11g group-by query-performance

在分析Oracle中SQL查询的性能时,我注意到一个奇怪的行为。我注意到Oracle的计划行为根据查询中使用的值而变化。

例如,这是我的表结构:


  CREATE TABLE "USAGE" 
   (    "ID" NUMBER(11,0) NOT NULL ENABLE, 
    "CREATED_DATE" TIMESTAMP (6), 
    "MODIFIED_DATE" TIMESTAMP (6),
    "PERIOD" TIMESTAMP (6) NOT NULL ENABLE, 
    "DOWNLOAD" NUMBER(19,0),
     PRIMARY KEY ("ID")
   );

  CREATE INDEX "USAGE_A0ACFA46" ON "USAGE" ("PERIOD");


  CREATE UNIQUE INDEX "USAG_PERIOD_772992E2_UNIQ" ON "USAGE" ("PERIOD");

当我获取以下查询的计划时,我看到该表可以通过INDEX RANGE SCAN访问,这是预期的:


explain plan for
select usg.period, sum(usg.download)
 from usage usg
 where usg.period>=TIMESTAMP '2018-11-30 00:00:00'
    group by usg.period;

SELECT PLAN_TABLE_OUTPUT FROM TABLE(DBMS_XPLAN.DISPLAY());
----------------------------------------------------------------------------------------------------------
| Id  | Operation                    | Name                      | Rows  | Bytes | Cost (%CPU)| Time     |
----------------------------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT             |                           |     1 |    18 |     3   (0)| 00:00:01 |
|   1 |  SORT GROUP BY NOSORT        |                           |     1 |    18 |     3   (0)| 00:00:01 |
|   2 |   TABLE ACCESS BY INDEX ROWID| USAGE                     |     1 |    18 |     3   (0)| 00:00:01 |
|*  3 |    INDEX RANGE SCAN          | USAG_PERIOD_E67F63D3_UNIQ |     1 |       |     2   (0)| 00:00:01 |
----------------------------------------------------------------------------------------------------------

但是,当我仅更改值时,我注意到该表是通过TABLE ACCESS FULL访问的,这对我来说很奇怪:


select usg.period, sum(usg.download)
 from usage usg
 where usg.period>=TIMESTAMP '2017-11-30 00:00:00'
    group by usg.period;

SELECT PLAN_TABLE_OUTPUT FROM TABLE(DBMS_XPLAN.DISPLAY());
----------------------------------------------------------------------------
| Id  | Operation          | Name  | Rows  | Bytes | Cost (%CPU)| Time     |
----------------------------------------------------------------------------
|   0 | SELECT STATEMENT   |       |   133 |  2394 |    69   (2)| 00:00:01 |
|   1 |  HASH GROUP BY     |       |   133 |  2394 |    69   (2)| 00:00:01 |
|*  2 |   TABLE ACCESS FULL| USAGE |  9505 |   167K|    68   (0)| 00:00:01 |
----------------------------------------------------------------------------

我的问题是,为什么会发生?不管值是多少,我都希望Oracle使用INDEX RANGE SCAN。

我的数据库是Oracle 11g

1 个答案:

答案 0 :(得分:4)

优化器可以根据数据量来决定是否使用单个索引,对于大量数据,full-scanthe index range scan更可取。

您的第二种情况似乎是在扫描间隔更长的情况下扫描更大的数据集。

例如,尝试将扫描限制在一个月内

第一季度:

select usg.period, sum(usg.download)
  from usage usg
 where usg.period between timestamp'2017-11-01 00:00:00' and timestamp'2017-11-30 00:00:00'
 group by usg.period;

第二季度:

select usg.period, sum(usg.download)
 from usage usg
 where usg.period between timestamp'2018-11-01 00:00:00' and timestamp'2018-11-30 00:00:00'
    group by usg.period;

对于查询Q1和Q2,您很可能会看到索引范围扫描,其费用接近值,具体取决于表的均匀填充数据。 索引最适合少数行。