TIMESTAMP 到 DATE 的转换问题 - 增加查询 运行 时间
Issue with TIMESTAMP to DATE conversion - increasing query run-time
我很想知道这个问题背后的原因是什么 -
例如我有一个查询
SELECT * FROM A WHERE A.DATE = (SELECT B.DATE FROM B)
这里 B.DATE 返回了一行,它的类型是 TIMESTAMP (3) 而 A.DATE 是 DATE 列。
所以 A table 很大,但是对于一个日期它只有 10 万行。上面的 SQL 处理了大约 1000 秒。
我这样做只用了 10 秒 -
SELECT * FROM A WHERE A.DATE = (SELECT CAST(B.DATE AS DATE) FROM B)
有人可以解释一下为什么 CAST 修复了 SQL 运行 时间吗?
Oracle 版本 - 19c
DATE
和 TIMESTAMP
之间的类型转换阻止了您在 "DATE"
列上定义的 索引使用 (BTW 不要对列名使用保留字 - DATE
必须被引用)
参见下面的示例
EXPLAIN PLAN SET STATEMENT_ID = 'jara1' into plan_table FOR
SELECT * FROM A WHERE A."DATE" = DATE'2021-01-02';
--
SELECT * FROM table(DBMS_XPLAN.DISPLAY('plan_table', 'jara1','ALL'));
-------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
-------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1 | 8 | 1 (0)| 00:00:01 |
|* 1 | INDEX RANGE SCAN| AI | 1 | 8 | 1 (0)| 00:00:01 |
-------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
1 - access("A"."DATE"=TO_DATE(' 2021-01-02 00:00:00', 'syyyy-mm-dd
hh24:mi:ss'))
;
EXPLAIN PLAN SET STATEMENT_ID = 'jara1' into plan_table FOR
SELECT * FROM A WHERE A."DATE" = TIMESTAMP'2021-01-02 00:00:00.000';
--
SELECT * FROM table(DBMS_XPLAN.DISPLAY('plan_table', 'jara1','ALL'));
--------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
--------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1000 | 8000 | 56 (6)| 00:00:01 |
|* 1 | TABLE ACCESS FULL| A | 1000 | 8000 | 56 (6)| 00:00:01 |
--------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
1 - filter(INTERNAL_FUNCTION("A"."DATE")=TIMESTAMP' 2021-01-02
00:00:00.000000000')
所以如果子查询 returns DATE
索引可以使用,但是如果 returns 一个 TIMESTAMP
列值必须转换为 TIMESTAMP
这会阻止 索引访问 (第二个示例)。
我很想知道这个问题背后的原因是什么 -
例如我有一个查询
SELECT * FROM A WHERE A.DATE = (SELECT B.DATE FROM B)
这里 B.DATE 返回了一行,它的类型是 TIMESTAMP (3) 而 A.DATE 是 DATE 列。
所以 A table 很大,但是对于一个日期它只有 10 万行。上面的 SQL 处理了大约 1000 秒。
我这样做只用了 10 秒 -
SELECT * FROM A WHERE A.DATE = (SELECT CAST(B.DATE AS DATE) FROM B)
有人可以解释一下为什么 CAST 修复了 SQL 运行 时间吗?
Oracle 版本 - 19c
DATE
和 TIMESTAMP
之间的类型转换阻止了您在 "DATE"
列上定义的 索引使用 (BTW 不要对列名使用保留字 - DATE
必须被引用)
参见下面的示例
EXPLAIN PLAN SET STATEMENT_ID = 'jara1' into plan_table FOR
SELECT * FROM A WHERE A."DATE" = DATE'2021-01-02';
--
SELECT * FROM table(DBMS_XPLAN.DISPLAY('plan_table', 'jara1','ALL'));
-------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
-------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1 | 8 | 1 (0)| 00:00:01 |
|* 1 | INDEX RANGE SCAN| AI | 1 | 8 | 1 (0)| 00:00:01 |
-------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
1 - access("A"."DATE"=TO_DATE(' 2021-01-02 00:00:00', 'syyyy-mm-dd
hh24:mi:ss'))
;
EXPLAIN PLAN SET STATEMENT_ID = 'jara1' into plan_table FOR
SELECT * FROM A WHERE A."DATE" = TIMESTAMP'2021-01-02 00:00:00.000';
--
SELECT * FROM table(DBMS_XPLAN.DISPLAY('plan_table', 'jara1','ALL'));
--------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
--------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1000 | 8000 | 56 (6)| 00:00:01 |
|* 1 | TABLE ACCESS FULL| A | 1000 | 8000 | 56 (6)| 00:00:01 |
--------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
1 - filter(INTERNAL_FUNCTION("A"."DATE")=TIMESTAMP' 2021-01-02
00:00:00.000000000')
所以如果子查询 returns DATE
索引可以使用,但是如果 returns 一个 TIMESTAMP
列值必须转换为 TIMESTAMP
这会阻止 索引访问 (第二个示例)。