Oracle SQL SELECT意外行为

时间:2016-01-13 15:04:07

标签: sql oracle

在遗留代码中,我发现了一些奇怪的SQL SELECT查询,导致我们的应用程序出错。我的Oracle版本 11.2.0.1.0 。下面(简化)代码:

DDL:

SELECT COUNT(*)
FROM
  (
    SELECT 
      B.ID,
      B.SURNAME,
      B.NAME
    FROM A
      LEFT JOIN B ON B.ID = A.ID_B
      LEFT OUTER JOIN (SELECT * FROM C WHERE ID = 10) C ON  1 = 1
    WHERE A.ID_B = 10
  );

选择

{{1}}

问题: 你可以帮我理解为什么select count(*)返回0,因为子查询返回1结果行? 当我删除'A_INDEX'时,两个选择都正常(count(*)返回1)。

2 个答案:

答案 0 :(得分:2)

如果没有索引,则带有count(*)的查询会执行此执行计划 Linux中的:版本11.2.0.3.0

------------------------------------------------------------------------------
| Id  | Operation             | Name | Rows  | Bytes | Cost (%CPU)| Time     |
------------------------------------------------------------------------------
|   0 | SELECT STATEMENT      |      |     1 |    15 |     5   (0)| 00:00:01 |
|   1 |  SORT AGGREGATE       |      |     1 |    15 |            |          |
|   2 |   MERGE JOIN OUTER    |      |     1 |    15 |     5   (0)| 00:00:01 |
|*  3 |    TABLE ACCESS FULL  | A    |     1 |    13 |     3   (0)| 00:00:01 |
|   4 |    BUFFER SORT        |      |     1 |     2 |     2   (0)| 00:00:01 |
|   5 |     VIEW              |      |     1 |     2 |     2   (0)| 00:00:01 |
|*  6 |      TABLE ACCESS FULL| C    |     1 |    13 |     2   (0)| 00:00:01 |
------------------------------------------------------------------------------

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

   3 - filter("A"."ID_B"=10)
   6 - filter("ID"=10)

请注意,Oracle不访问表B并在A和C上执行外连接, 这导致结果1 - 正确

使用A 上的索引 - Oracle打开CARTESIAN JOIN导致结果1 * 0 = 0(此联接不是OUTER

---------------------------------------------------------------------------------
| Id  | Operation             | Name    | Rows  | Bytes | Cost (%CPU)| Time     |
---------------------------------------------------------------------------------
|   0 | SELECT STATEMENT      |         |     1 |    15 |     2   (0)| 00:00:01 |
|   1 |  SORT AGGREGATE       |         |     1 |    15 |            |          |
|   2 |   MERGE JOIN CARTESIAN|         |     1 |    15 |     2   (0)| 00:00:01 |
|   3 |    VIEW               |         |     1 |     2 |     2   (0)| 00:00:01 |
|*  4 |     TABLE ACCESS FULL | C       |     1 |    13 |     2   (0)| 00:00:01 |
|   5 |    BUFFER SORT        |         |     1 |    13 |     2   (0)| 00:00:01 |
|*  6 |     INDEX RANGE SCAN  | A_INDEX |     1 |    13 |     0   (0)| 00:00:01 |
---------------------------------------------------------------------------------


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

   4 - filter("ID"=10)
   6 - access("A"."ID_B"=10) 

对于坏消息感到抱歉,IMO在Oracle中这是一个错误的优化,唯一的机会是打开SR(或者使用drop index或重新构造查询来解决它)。

对于completness,使用提示/*+ NO_QUERY_TRANSFORMATION */的查询计划 现在可以访问表B并且两个连接都是外部的,因此它可以正常工作。

------------------------------------------------------------------------------------------
| Id  | Operation                      | Name    | Rows  | Bytes | Cost (%CPU)| Time     |
------------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT               |         |     1 |    80 |     4   (0)| 00:00:01 |
|   1 |  MERGE JOIN OUTER              |         |     1 |    80 |     4   (0)| 00:00:01 |
|   2 |   MERGE JOIN OUTER             |         |     1 |    80 |     2   (0)| 00:00:01 |
|*  3 |    INDEX RANGE SCAN            | A_INDEX |     1 |    13 |     1   (0)| 00:00:01 |
|   4 |    BUFFER SORT                 |         |     1 |    67 |     1   (0)| 00:00:01 |
|   5 |     TABLE ACCESS BY INDEX ROWID| B       |     1 |    67 |     1   (0)| 00:00:01 |
|*  6 |      INDEX UNIQUE SCAN         | PK_B    |     1 |       |     0   (0)| 00:00:01 |
|   7 |   BUFFER SORT                  |         |     1 |       |     3   (0)| 00:00:01 |
|   8 |    VIEW                        |         |     1 |       |     2   (0)| 00:00:01 |
|*  9 |     TABLE ACCESS FULL          | C       |     1 |    13 |     2   (0)| 00:00:01 |
------------------------------------------------------------------------------------------

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

   3 - access("A"."ID_B"=10)
   6 - access("B"."ID"(+)=10)
   9 - filter("ID"=10)

答案 1 :(得分:2)

在11.2.0.4中,无论是否有索引,我得到1的计数。有索引的计划:

---------------------------------------------------------------------------------
| Id  | Operation             | Name    | Rows  | Bytes | Cost (%CPU)| Time     |
---------------------------------------------------------------------------------
|   0 | SELECT STATEMENT      |         |     1 |    13 |     3   (0)| 00:00:01 |
|   1 |  SORT AGGREGATE       |         |     1 |    13 |            |          |
|   2 |   MERGE JOIN OUTER    |         |     1 |    13 |     3   (0)| 00:00:01 |
|*  3 |    INDEX RANGE SCAN   | A_INDEX |     1 |    13 |     1   (0)| 00:00:01 |
|   4 |    BUFFER SORT        |         |     1 |       |     2   (0)| 00:00:01 |
|   5 |     VIEW              |         |     1 |       |     2   (0)| 00:00:01 |
|*  6 |      TABLE ACCESS FULL| C       |     1 |    13 |     2   (0)| 00:00:01 |
---------------------------------------------------------------------------------

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

   3 - access("A"."ID_B"=10)                                                     
   6 - filter("ID"=10)                                                           

没有:

------------------------------------------------------------------------------   
| Id  | Operation             | Name | Rows  | Bytes | Cost (%CPU)| Time     |   
------------------------------------------------------------------------------   
|   0 | SELECT STATEMENT      |      |     1 |    13 |     5   (0)| 00:00:01 |   
|   1 |  SORT AGGREGATE       |      |     1 |    13 |            |          |   
|   2 |   MERGE JOIN OUTER    |      |     1 |    13 |     5   (0)| 00:00:01 |   
|*  3 |    TABLE ACCESS FULL  | A    |     1 |    13 |     3   (0)| 00:00:01 |   
|   4 |    BUFFER SORT        |      |     1 |       |     2   (0)| 00:00:01 |   
|   5 |     VIEW              |      |     1 |       |     2   (0)| 00:00:01 |   
|*  6 |      TABLE ACCESS FULL| C    |     1 |    13 |     2   (0)| 00:00:01 |   
------------------------------------------------------------------------------   

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

   3 - filter("A"."ID_B"=10)                                                     
   6 - filter("ID"=10)          

由于这不是11.2.0.3中的行为,因此可能修复了11.2.0.4补丁集(或其中一个CPU;此环境包括2015年10月的CPU,没有其他补丁)。部分基于我们的评论,/*+ NO_QUERY_TRANSFORMATION */解决它,这看起来类似于错误12638091,但它看起来不应该影响11.2.0.3 - 只有这样才能确保提出服务请求。 / p>