【问题标题】:Unexpected query results in Oracle dbOracle 数据库中的意外查询结果
【发布时间】:2018-06-06 09:18:03
【问题描述】:

我们有 Oracle 12.2.0.1.0 数据库。我们像这样创建一个简单的表:

CREATE TABLE TABLE1 (DATE1 TIMESTAMP (6));
INSERT INTO TABLE1 VALUES (TIMESTAMP'2018-05-30 00:00:00');
INSERT INTO TABLE1 VALUES (TIMESTAMP'2018-05-30 00:00:00');

当我们使用以下两个 select 语句进行查询时,我们会得到不同的结果。第一个按预期返回两行,而第二个没有。

SELECT T1.*, NVL(T2.DATE1, TIMESTAMP'1900-01-01 00:00:00')
FROM TABLE1 T1
LEFT JOIN TABLE1 T2
ON 1 = 0
WHERE T1.DATE1 > NVL(T2.DATE1, TIMESTAMP'1900-01-01 00:00:00');

SELECT T1.*, NVL(T2.DATE1, TIMESTAMP'1900-01-01 00:00:00')
FROM TABLE1 T1
LEFT JOIN TABLE1 T2
ON T1.DATE1 || '---' = '-'
WHERE T1.DATE1 > NVL(T2.DATE1, TIMESTAMP'1900-01-01 00:00:00');

T1 和 T2 是相同的 TABLE1。我们自己加入它。

请告知为什么会这样。谢谢。

【问题讨论】:

  • T1.DATE1 TABLE1 T1 LEFT JOIN TABLE1 T2 ?? T1.Date1??也许您想将其与某些东西进行比较?还是 use is not null 代替?
  • @KristjanKica 问题很简单。 LEFT JOIN 应该产生相同的结果 (1=0) 或 (T1.DATE1 || '---' = '-') 两者都是错误的,并且在第二种情况下,Oracle 会以不同的方式评估它。
  • 如果它有用,它在 Oracle Database 12c 企业版版本 12.1.0.2.0 - 64 位生产上运行良好
  • @KristjanKica 不,我们希望完全像这样使用查询。基本上,我们希望在任何评估为 False 的条件下加入。第一种情况是 1=0,第二种情况是使用 T1.DATE1。

标签: sql oracle


【解决方案1】:

似乎优化器对如此多级别的混淆连接条件感到困惑。

第一个查询产生以下执行计划:

SQL_ID  9k6g3m0xs31w7, child number 1
-------------------------------------
select t1.*, nvl(t2.date1, timestamp'1900-01-01 00:00:00') from table1 
t1   left join table1 t2 on 1 = 0 where t1.date1 > nvl(t2.date1, 
timestamp'1900-01-01 00:00:00')

Plan hash value: 963482612

-----------------------------------------------------------------------------------------------------------
| Id  | Operation         | Name   | Starts | E-Rows |E-Bytes| Cost (%CPU)| A-Rows |   A-Time   | Buffers |
-----------------------------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT  |        |      1 |        |       |     3 (100)|      2 |00:00:00.01 |       7 |
|*  1 |  TABLE ACCESS FULL| TABLE1 |      1 |      2 |    26 |     3   (0)|      2 |00:00:00.01 |       7 |
-----------------------------------------------------------------------------------------------------------

Query Block Name / Object Alias (identified by operation id):
-------------------------------------------------------------

   1 - SEL$F7AF7B7D / T1@SEL$1

Predicate Information (identified by operation id):
---------------------------------------------------

   1 - filter("T1"."DATE1">TIMESTAMP' 1900-01-01 00:00:00.000000000')

因此,规划器正确地看到自联接是不必要的,并将联接表上的 NVL() 条件替换为列本身的条件。

显然,这种“替换”条件在 12.2 中无法正常工作。

第二个查询产生以下计划:

SQL_ID  3twykk3kcyyxy, child number 1
-------------------------------------
select t1.*, nvl(t2.date1, timestamp'1900-01-01 00:00:00') from table1 
t1 left join table1 t2   on t1.date1 || '---' = '-' where t1.date1 > 
nvl(t2.date1, timestamp'1900-01-01 00:00:00')

Plan hash value: 736255932

----------------------------------------------------------------------------------------------------------------------------------------------------
| Id  | Operation              | Name            | Starts | E-Rows |E-Bytes| Cost (%CPU)| A-Rows |   A-Time   | Buffers |  OMem |  1Mem | Used-Mem |
----------------------------------------------------------------------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT       |                 |      1 |        |       |     8 (100)|      0 |00:00:00.01 |       7 |       |       |          |
|*  1 |  FILTER                |                 |      1 |        |       |            |      0 |00:00:00.01 |       7 |       |       |          |
|   2 |   MERGE JOIN OUTER     |                 |      1 |      1 |    26 |     8  (25)|      2 |00:00:00.01 |       7 |       |       |          |
|   3 |    SORT JOIN           |                 |      1 |      2 |    26 |     4  (25)|      2 |00:00:00.01 |       7 |  2048 |  2048 | 2048  (0)|
|   4 |     TABLE ACCESS FULL  | TABLE1          |      1 |      2 |    26 |     3   (0)|      2 |00:00:00.01 |       7 |       |       |          |
|*  5 |    SORT JOIN           |                 |      2 |      2 |    26 |     4  (25)|      0 |00:00:00.01 |       0 |  1024 |  1024 |          |
|   6 |     VIEW               | VW_LAT_C83A7ED5 |      2 |      2 |    26 |     3   (0)|      0 |00:00:00.01 |       0 |       |       |          |
|*  7 |      FILTER            |                 |      2 |        |       |            |      0 |00:00:00.01 |       0 |       |       |          |
|   8 |       TABLE ACCESS FULL| TABLE1          |      0 |      2 |    26 |     3   (0)|      0 |00:00:00.01 |       0 |       |       |          |
----------------------------------------------------------------------------------------------------------------------------------------------------

Query Block Name / Object Alias (identified by operation id):
-------------------------------------------------------------

   1 - SEL$F7AF7B7D
   4 - SEL$F7AF7B7D / T1@SEL$1
   6 - SEL$BCD4421C / VW_LAT_AE9E49E8@SEL$AE9E49E8
   7 - SEL$BCD4421C
   8 - SEL$BCD4421C / T2@SEL$1

Predicate Information (identified by operation id):
---------------------------------------------------

   1 - filter("T1"."DATE1">NVL("ITEM_1",TIMESTAMP' 1900-01-01 00:00:00.000000000'))
   5 - access(INTERNAL_FUNCTION("T1"."DATE1")>NVL("ITEM_1",TIMESTAMP' 1900-01-01 00:00:00.000000000'))
   7 - filter(INTERNAL_FUNCTION("T1"."DATE1")||'---'='-')

所以优化器用一些 ITEM1 占位符替换了对表列的引用 - 而步骤 access(INTERNAL_FUNCTION("T1"."DATE1")>NVL("ITEM_1",TIMESTAMP' 1900-01-01 00:00:00.000000000')) 把事情搞砸了。

与 12.1 的计划基本相同,唯一的区别是谓词中缺少 access() 部分,所以我猜在 12.2 中替换有些错误(准确地说,我的版本是:12.2.0.1。 0)

【讨论】:

    猜你喜欢
    • 2013-02-19
    • 2013-01-04
    • 2023-03-05
    • 2010-11-25
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2023-03-22
    • 2017-10-17
    相关资源
    最近更新 更多