2016-01-13 3 views
1

В устаревшем коде я нашел какой-то странный запрос SQL SELECT, который вызвал ошибку в нашем приложении. Моя версия Oracle 11.2.0.1.0. Ниже (упрощенный) Код:Oracle SQL SELECT неожиданное поведение

DDL:

DROP TABLE A; 
DROP TABLE B; 
DROP TABLE C; 

CREATE TABLE "A" 
    (
    "ID_B"    NUMBER NOT NULL 
); 

CREATE INDEX "A_INDEX" ON "A"("ID_B"); 

CREATE TABLE "B" 
    (
    "ID"    NUMBER NOT NULL, 
    "NAME"    VARCHAR2(50 BYTE), 
    "SURNAME"   VARCHAR2(50 BYTE), 
    CONSTRAINT "PK_B" PRIMARY KEY ("ID") 
); 

CREATE TABLE "C" 
    (
    "ID"    NUMBER NOT NULL 
); 


INSERT INTO A(ID_B) VALUES (10); 
INSERT INTO B(ID, SURNAME, NAME) VALUES(10, 'LUCKY', 'LUKE'); 
COMMIT; 

ВЫБРАТЬ:

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 
); 

ПРОБЛЕМА: могли бы вы помочь мне понять, почему выберите COUNT (*) возвращает 0, как результат по суб-запросу возвращает 1 строку результата? Когда я отбрасываю 'A_INDEX', оба выбирают отлично (count (*) возвращает 1).

+0

Пожалуйста, напишите 'EXPLAIN PLAN FOR SELECT ...' для обоих случаев – lad2025

+0

Это ... странно, и он корректно работает с индексом, если вы измените внешнее соединение, чтобы использовать c, id = a.id_b вместо из 1 = 1, которая в любом случае является нечетной конструкцией. –

+0

@ lad2025 мой план выполнения точно такой же, как и ниже –

ответ

2

без индекса запроса с COUNT (*) шляпа этот план выполнения в Linux: Version 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 не имеет доступа к таблице В и выполняет внешнее соединение на а и с, , что приводит к 1 результат - правильный

с указателем на - Oracle Open CARTESIAN JOIN, который приводит к результату 1 * 0 = 0 (Thi s присоединиться не 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) 

Извините за плохие новости, ИМО это неправильная оптимизация в Oracle, единственный шанс открыть SR (или обойти его с индексом падения или переформулировать запрос).

Для Комплектности, план запроса с намеком /*+ 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) 
+0

Попробовал добавить подсказку/* + NO_QUERY_TRANSFORMATION * /, во внешнем запросе она работает хорошо; (тестируется на Oracle 11.2.0.3.0) – Aleksej

+0

@Aleksej правильный, я добавил намеченный план, чтобы понять, почему. –

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, эта среда включает процессор October October 2015, без дополнительных исправлений). Частично основанный на нашем комментарии, что /*+ NO_QUERY_TRANSFORMATION */ работает вокруг него, это похоже на ошибку 12638091, но не похоже, что это должно повлиять на 11.2.0.3 - только, чтобы быть уверенным в том, что нужно поднять запрос на обслуживание.

+0

Я постараюсь проверить его на 11.2.0.4 - спасибо за подсказку –

+1

@Mydory - точнее, это было на 11.2.0.4.7 (то есть в том числе обновление критического обновления в октябре 2015 года), на Linux. Я не заметил ничего очевидного в опубликованной информации о наборе патчей или процессоре. –

Смежные вопросы