我的理解是 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
不得不这样做似乎是“错误的”或“骇人听闻的”。希望得到这个社区的澄清。