4

我的理解是 Date 数据类型没有小数秒。如果这是真的,那么为什么下面的三个查询不是全部都有Pstart=6,为什么它们不是都没有过滤谓词?

也就是说,对于 Date 数据类型,以下两个是否在逻辑上是等价的?

:x > to_date('20210605 00:00:00','YYYYMMDD HH24:MI:SS')

:x >= to_date('20210605 00:00:01','YYYYMMDD HH24:MI:SS')

Oracle 12.1 企业版。

提前致谢。

设置:(虽然这对于这个问题来说可能有点太多了,但我在其他测试中使用了这个设置)

drop table p;

create table p
  (
    grp CHAR(3 byte)
    , dt DATE
    , payment_amount NUMBER
  )
  nocompress 
  tablespace data
  partition by LIST (grp)
  subpartition by range (dt)
  ( partition P_P_A values ('A')
    ( subpartition P_P_A_20210410 values less than (to_date('20210410 00:00:01','YYYYMMDD HH24:MI:SS'))
     ,subpartition P_P_A_20210424 values less than (to_date('20210424 00:00:01','YYYYMMDD HH24:MI:SS'))
     ,subpartition P_P_A_20210508 values less than (to_date('20210508 00:00:01','YYYYMMDD HH24:MI:SS'))
     ,subpartition P_P_A_20210522 values less than (to_date('20210522 00:00:01','YYYYMMDD HH24:MI:SS'))
     ,subpartition P_P_A_20210605 values less than (to_date('20210605 00:00:01','YYYYMMDD HH24:MI:SS'))
     ,subpartition P_P_A_20210619 values less than (to_date('20210619 00:00:01','YYYYMMDD HH24:MI:SS'))
     ,subpartition P_P_A_20210703 values less than (to_date('20210703 00:00:01','YYYYMMDD HH24:MI:SS'))
    )
   ,partition P_P_B values ('B')
    ( subpartition P_P_B_20210410 values less than (to_date('20210410 00:00:01','YYYYMMDD HH24:MI:SS'))
     ,subpartition P_P_B_20210424 values less than (to_date('20210424 00:00:01','YYYYMMDD HH24:MI:SS'))
     ,subpartition P_P_B_20210508 values less than (to_date('20210508 00:00:01','YYYYMMDD HH24:MI:SS'))
     ,subpartition P_P_B_20210522 values less than (to_date('20210522 00:00:01','YYYYMMDD HH24:MI:SS'))
     ,subpartition P_P_B_20210605 values less than (to_date('20210605 00:00:01','YYYYMMDD HH24:MI:SS'))
     ,subpartition P_P_B_20210619 values less than (to_date('20210619 00:00:01','YYYYMMDD HH24:MI:SS'))
     ,subpartition P_P_B_20210703 values less than (to_date('20210703 00:00:01','YYYYMMDD HH24:MI:SS'))
    )
   ,partition P_P_C values ('C')
    ( subpartition P_P_C_20210410 values less than (to_date('20210410 00:00:01','YYYYMMDD HH24:MI:SS'))
     ,subpartition P_P_C_20210424 values less than (to_date('20210424 00:00:01','YYYYMMDD HH24:MI:SS'))
     ,subpartition P_P_C_20210508 values less than (to_date('20210508 00:00:01','YYYYMMDD HH24:MI:SS'))
     ,subpartition P_P_C_20210522 values less than (to_date('20210522 00:00:01','YYYYMMDD HH24:MI:SS'))
     ,subpartition P_P_C_20210605 values less than (to_date('20210605 00:00:01','YYYYMMDD HH24:MI:SS'))
     ,subpartition P_P_C_20210619 values less than (to_date('20210619 00:00:01','YYYYMMDD HH24:MI:SS'))
     ,subpartition P_P_C_20210703 values less than (to_date('20210703 00:00:01','YYYYMMDD HH24:MI:SS'))
    )
  )
;
insert 
  into p
     ( grp
      ,dt
      ,payment_amount
     )
with "D" as (select /*+ materialize */ 1 from dual connect by level <= 1000)
select case mod(rownum, 3) when 1 then 'A' when 2 then 'B' when 0 then 'C' end
      , to_date('20210410','YYYYMMDD') + 14 * mod(rownum, 7)
      , dbms_random.value(500, 5000)
  from "D", "D"
;
commit;
exec dbms_stats.gather_table_stats(null, 'P');

查询 1 - 严格不等式

select sum(P.payment_amount) 
  from p "P" 
 where P.grp = 'B'
       and P.dt > to_date('20210605 00:00:00','YYYYMMDD HH24:MI:SS') 
       and P.dt < to_date('20210703 00:00:01','YYYYMMDD HH24:MI:SS')
;  
----------------------------------------------------------------------------------------------------
| id  | Operation                  | name  | rows  | Bytes | cost (%CPU)| time     | Pstart| Pstop |
----------------------------------------------------------------------------------------------------
|   0 | select statement           |       |     1 |    34 |  2152   (1)| 00:00:01 |       |       |
|   1 |  sort AGGREGATE            |       |     1 |    34 |            |          |       |       |
|   2 |   partition LIST single    |       |   111K|  3689K|  2152   (1)| 00:00:01 |   key |   key |
|   3 |    partition range ITERATOR|       |   111K|  3689K|  2152   (1)| 00:00:01 |     5 |     7 |
|*  4 |     table access full      | p     |   111K|  3689K|  2152   (1)| 00:00:01 |       |       |
----------------------------------------------------------------------------------------------------
  
Predicate Information (identified by operation id):
---------------------------------------------------

   4 - filter("P"."DT">to_date(' 2021-06-05 00:00:00', 'syyyy-mm-dd hh24:mi:ss'))

查询 2 - 非严格不等式:

select sum(P.payment_amount) 
  from p "P" 
 where P.grp = 'B'
       and P.dt >= to_date('20210605 00:00:01','YYYYMMDD HH24:MI:SS') 
       and P.dt <= to_date('20210703 00:00:00','YYYYMMDD HH24:MI:SS')
;  
----------------------------------------------------------------------------------------------------
| id  | Operation                  | name  | rows  | Bytes | cost (%CPU)| time     | Pstart| Pstop |
----------------------------------------------------------------------------------------------------
|   0 | select statement           |       |     1 |    34 |  1436   (1)| 00:00:01 |       |       |
|   1 |  sort AGGREGATE            |       |     1 |    34 |            |          |       |       |
|   2 |   partition LIST single    |       |   158K|  5270K|  1436   (1)| 00:00:01 |   key |   key |
|   3 |    partition range ITERATOR|       |   158K|  5270K|  1436   (1)| 00:00:01 |     6 |     7 |
|*  4 |     table access full      | p     |   158K|  5270K|  1436   (1)| 00:00:01 |       |       |
----------------------------------------------------------------------------------------------------
  
Predicate Information (identified by operation id):
---------------------------------------------------

   4 - filter("P"."DT"<=to_date(' 2021-07-03 00:00:00', 'syyyy-mm-dd hh24:mi:ss'))

查询 3 - 无谓词:

select sum(P.payment_amount) 
  from p "P" 
 where P.grp = 'B'
       and P.dt >= to_date('20210605 00:00:01','YYYYMMDD HH24:MI:SS') 
       and P.dt < to_date('20210703 00:00:01','YYYYMMDD HH24:MI:SS')
; 
----------------------------------------------------------------------------------------------------
| id  | Operation                  | name  | rows  | Bytes | cost (%CPU)| time     | Pstart| Pstop |
----------------------------------------------------------------------------------------------------
|   0 | select statement           |       |     1 |    34 |  1436   (1)| 00:00:01 |       |       |
|   1 |  sort AGGREGATE            |       |     1 |    34 |            |          |       |       |
|   2 |   partition LIST single    |       |   158K|  5270K|  1436   (1)| 00:00:01 |   key |   key |
|   3 |    partition range ITERATOR|       |   158K|  5270K|  1436   (1)| 00:00:01 |     6 |     7 |
|   4 |     table access full      | p     |   158K|  5270K|  1436   (1)| 00:00:01 |       |       |
----------------------------------------------------------------------------------------------------

编辑:附录以阐明上述实验性子分区定义的用例和动机。

应用程序的当前子分区定义具有以下形式。

   ,partition P_P_B values ('B')
    ( subpartition P_P_B_20210410 values less than (to_date('20210411','YYYYMMDD'))
     ,subpartition P_P_B_20210424 values less than (to_date('20210425','YYYYMMDD'))
     ,subpartition P_P_B_20210508 values less than (to_date('20210509','YYYYMMDD'))
     ,subpartition P_P_B_20210522 values less than (to_date('20210523','YYYYMMDD'))
     ,subpartition P_P_B_20210605 values less than (to_date('20210606','YYYYMMDD'))
     ,subpartition P_P_B_20210619 values less than (to_date('20210620','YYYYMMDD'))
     ,subpartition P_P_B_20210703 values less than (to_date('20210704','YYYYMMDD'))
     ,subpartition P_P_B_20210717 values less than (to_date('20210718','YYYYMMDD'))
    )

应用程序生成带有谓词的查询,如下所示。

P.dt between to_date('20210606 00:00:00','YYYYMMDD HH24:MI:SS') 
         and to_date('20210703 23:59:59','YYYYMMDD HH24:MI:SS') 

这会在范围的上端产生一个过滤谓词。

 4 - filter("P"."DT"<=to_date(' 2021-07-03 23:59:59', 'syyyy-mm-dd hh24:mi:ss'))

因此,以下两个表达式看似不等价的混淆促使了这篇文章。

P.dt <= to_date('20210703 23:59:59','YYYYMMDD HH24:MI:SS') 

P.dt < to_date('20210704 00:00:00','YYYYMMDD HH24:MI:SS') 

如果修改应用程序以生成谓词,则可以避免此过滤谓词,如下所示。

P.dt >= to_date('20210606 00:00:00','YYYYMMDD HH24:MI:SS') 
and P.dt < to_date('20210703 00:00:00','YYYYMMDD HH24:MI:SS') + 1

不得不这样做似乎是“错误的”或“骇人听闻的”。希望得到这个社区的澄清。

4

0 回答 0