将解释计划中的日期显示为文字
Display dates in explain plan as literals
SELECT DISTINCT i.name, i.daily_cost
FROM edu_event.items i
WHERE i.purchase_date BETWEEN DATE'2015-01-01' AND DATE'2015-12-31';
对于此查询,选择了以下执行计划:
----------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
----------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 5750 | 213K| 206 (1)| 00:00:01 |
| 1 | HASH UNIQUE | | 5750 | 213K| 206 (1)| 00:00:01 |
|* 2 | TABLE ACCESS FULL| ITEMS | 5750 | 213K| 205 (1)| 00:00:01 |
----------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
2 - filter("I"."PURCHASE_DATE">=TO_DATE('2015-01-01 00:00:00', 'syyyy-mm-dd hh24:mi:ss') AND "I"."PURCHASE_DATE"<=TO_DATE('2015-12-31 00:00:00', 'syyyy-mm-dd hh24:mi:ss'))
如您所见,原始日期文字已替换为 to_date
函数。我可以以某种方式禁用它吗?这种格式更大,但它没有提供更多信息,所以我不需要它。 SQL 开发人员可以通过编程将其转换回来吗?
这是 Oracle 在幕后所做的,并不是一个特殊的 SQL 开发人员视图。无法修改格式:
SQL> explain plan for
2 with rec (d) as (select sysdate from dual)
3 select *
4 from rec
5 where d > date '2018-01-01';
Explained.
SQL> select * from table(dbms_xplan.display);
PLAN_TABLE_OUTPUT
--------------------------------------------------------------------------------
Plan hash value: 4034615273
-----------------------------------------------------------------
| Id | Operation | Name | Rows | Cost (%CPU)| Time |
-----------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1 | 2 (0)| 00:00:01 |
|* 1 | FILTER | | | | |
| 2 | FAST DUAL | | 1 | 2 (0)| 00:00:01 |
-----------------------------------------------------------------
Predicate Information (identified by operation id):
PLAN_TABLE_OUTPUT
-----------------------------------------------------------------------------------------------------------------------------------
1 - filter(SYSDATE@!>TO_DATE(' 2018-01-01 00:00:00', 'syyyy-mm-dd
hh24:mi:ss'))
15 rows selected.
可以通过DBMS_XPLAN.DISPLAY()的format参数去掉predicate信息,但是不能修改它的样子
SQL> select * from table(dbms_xplan.display(null, null, '-PREDICATE'));
PLAN_TABLE_OUTPUT
--------------------------------------------------------------------------------
Plan hash value: 4034615273
-----------------------------------------------------------------
| Id | Operation | Name | Rows | Cost (%CPU)| Time |
-----------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1 | 2 (0)| 00:00:01 |
| 1 | FILTER | | | | |
| 2 | FAST DUAL | | 1 | 2 (0)| 00:00:01 |
-----------------------------------------------------------------
9 rows selected.
如其他答案所述,这就是 Oracle 重写 DATE
文字的方式。
例如,在使用 DATE
文字定义分区 table 时,如下所示..
create table TEST
(id NUMBER,
PART_DATE DATE
)
PARTITION BY RANGE (PART_DATE)
INTERVAL(NUMTOYMINTERVAL(1, 'MONTH'))
(
PARTITION p1 VALUES LESS THAN (DATE'2018-08-01'),
PARTITION p2 VALUES LESS THAN (DATE'2018-09-01'),
PARTITION p3 VALUES LESS THAN (DATE'2018-10-01')
);
...您将分区的 HIGH_VALUES
视为 to_date
函数调用:
TO_DATE(' 2018-08-01 00:00:00', 'SYYYY-MM-DD HH24:MI:SS', 'NLS_CALENDAR=GREGORIAN')
TO_DATE(' 2018-09-01 00:00:00', 'SYYYY-MM-DD HH24:MI:SS', 'NLS_CALENDAR=GREGORIAN')
TO_DATE(' 2018-10-01 00:00:00', 'SYYYY-MM-DD HH24:MI:SS', 'NLS_CALENDAR=GREGORIAN')
什么是重要的 - Oracle 了解日期的value
.
例如这个查询...
select * from TEST where PART_DATE = DATE'2018-09-15';
... 生成以下执行计划
-----------------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time | Pstart| Pstop |
-----------------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1 | 22 | 2 (0)| 00:00:01 | | |
| 1 | PARTITION RANGE SINGLE| | 1 | 22 | 2 (0)| 00:00:01 | 3 | 3 |
|* 2 | TABLE ACCESS FULL | TEST | 1 | 22 | 2 (0)| 00:00:01 | 3 | 3 |
-----------------------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
2 - filter("PART_DATE"=TO_DATE(' 2018-09-15 00:00:00', 'syyyy-mm-dd hh24:mi:ss'))
请注意,FILTER
谓词使用 to_date
函数调用, 但 Pstart
和 Pstop
指向单个分区(#3 )
这意味着,Oracle 在根据 DATE 值进行解析时知道将访问哪个分区(并且可以在优化时从这些知识中获益)。
简而言之 - 是的,围绕日期字符串有一个函数调用,但这与对列的函数调用禁止索引访问的情况不可比。
相反,在使用谓词 PART_DATE = SYSDATE
访问上述 table 时,您会得到一个指向 KEY
分区的执行计划。
|* 2 | TABLE ACCESS FULL | TEST | 1 | 22 | 2 (0)| 00:00:01 | KEY | KEY |
这意味着 Oracle 知道它只会访问一个分区,但不知道是哪一个。
SELECT DISTINCT i.name, i.daily_cost
FROM edu_event.items i
WHERE i.purchase_date BETWEEN DATE'2015-01-01' AND DATE'2015-12-31';
对于此查询,选择了以下执行计划:
----------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
----------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 5750 | 213K| 206 (1)| 00:00:01 |
| 1 | HASH UNIQUE | | 5750 | 213K| 206 (1)| 00:00:01 |
|* 2 | TABLE ACCESS FULL| ITEMS | 5750 | 213K| 205 (1)| 00:00:01 |
----------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
2 - filter("I"."PURCHASE_DATE">=TO_DATE('2015-01-01 00:00:00', 'syyyy-mm-dd hh24:mi:ss') AND "I"."PURCHASE_DATE"<=TO_DATE('2015-12-31 00:00:00', 'syyyy-mm-dd hh24:mi:ss'))
如您所见,原始日期文字已替换为 to_date
函数。我可以以某种方式禁用它吗?这种格式更大,但它没有提供更多信息,所以我不需要它。 SQL 开发人员可以通过编程将其转换回来吗?
这是 Oracle 在幕后所做的,并不是一个特殊的 SQL 开发人员视图。无法修改格式:
SQL> explain plan for
2 with rec (d) as (select sysdate from dual)
3 select *
4 from rec
5 where d > date '2018-01-01';
Explained.
SQL> select * from table(dbms_xplan.display);
PLAN_TABLE_OUTPUT
--------------------------------------------------------------------------------
Plan hash value: 4034615273
-----------------------------------------------------------------
| Id | Operation | Name | Rows | Cost (%CPU)| Time |
-----------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1 | 2 (0)| 00:00:01 |
|* 1 | FILTER | | | | |
| 2 | FAST DUAL | | 1 | 2 (0)| 00:00:01 |
-----------------------------------------------------------------
Predicate Information (identified by operation id):
PLAN_TABLE_OUTPUT
-----------------------------------------------------------------------------------------------------------------------------------
1 - filter(SYSDATE@!>TO_DATE(' 2018-01-01 00:00:00', 'syyyy-mm-dd
hh24:mi:ss'))
15 rows selected.
可以通过DBMS_XPLAN.DISPLAY()的format参数去掉predicate信息,但是不能修改它的样子
SQL> select * from table(dbms_xplan.display(null, null, '-PREDICATE'));
PLAN_TABLE_OUTPUT
--------------------------------------------------------------------------------
Plan hash value: 4034615273
-----------------------------------------------------------------
| Id | Operation | Name | Rows | Cost (%CPU)| Time |
-----------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1 | 2 (0)| 00:00:01 |
| 1 | FILTER | | | | |
| 2 | FAST DUAL | | 1 | 2 (0)| 00:00:01 |
-----------------------------------------------------------------
9 rows selected.
如其他答案所述,这就是 Oracle 重写 DATE
文字的方式。
例如,在使用 DATE
文字定义分区 table 时,如下所示..
create table TEST
(id NUMBER,
PART_DATE DATE
)
PARTITION BY RANGE (PART_DATE)
INTERVAL(NUMTOYMINTERVAL(1, 'MONTH'))
(
PARTITION p1 VALUES LESS THAN (DATE'2018-08-01'),
PARTITION p2 VALUES LESS THAN (DATE'2018-09-01'),
PARTITION p3 VALUES LESS THAN (DATE'2018-10-01')
);
...您将分区的 HIGH_VALUES
视为 to_date
函数调用:
TO_DATE(' 2018-08-01 00:00:00', 'SYYYY-MM-DD HH24:MI:SS', 'NLS_CALENDAR=GREGORIAN')
TO_DATE(' 2018-09-01 00:00:00', 'SYYYY-MM-DD HH24:MI:SS', 'NLS_CALENDAR=GREGORIAN')
TO_DATE(' 2018-10-01 00:00:00', 'SYYYY-MM-DD HH24:MI:SS', 'NLS_CALENDAR=GREGORIAN')
什么是重要的 - Oracle 了解日期的value
.
例如这个查询...
select * from TEST where PART_DATE = DATE'2018-09-15';
... 生成以下执行计划
-----------------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time | Pstart| Pstop |
-----------------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1 | 22 | 2 (0)| 00:00:01 | | |
| 1 | PARTITION RANGE SINGLE| | 1 | 22 | 2 (0)| 00:00:01 | 3 | 3 |
|* 2 | TABLE ACCESS FULL | TEST | 1 | 22 | 2 (0)| 00:00:01 | 3 | 3 |
-----------------------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
2 - filter("PART_DATE"=TO_DATE(' 2018-09-15 00:00:00', 'syyyy-mm-dd hh24:mi:ss'))
请注意,FILTER
谓词使用 to_date
函数调用, 但 Pstart
和 Pstop
指向单个分区(#3 )
这意味着,Oracle 在根据 DATE 值进行解析时知道将访问哪个分区(并且可以在优化时从这些知识中获益)。
简而言之 - 是的,围绕日期字符串有一个函数调用,但这与对列的函数调用禁止索引访问的情况不可比。
相反,在使用谓词 PART_DATE = SYSDATE
访问上述 table 时,您会得到一个指向 KEY
分区的执行计划。
|* 2 | TABLE ACCESS FULL | TEST | 1 | 22 | 2 (0)| 00:00:01 | KEY | KEY |
这意味着 Oracle 知道它只会访问一个分区,但不知道是哪一个。