Оптимизация запросов Не в левом внешнем объединении

Рассмотрим следующие таблицы;

тест

SQL> desc test;
 Name                                      Null?    Type
 ----------------------------------------- -------- ----------------------------
 NUM                                       NOT NULL NUMBER
 NUM2                                               NUMBER(10)
 NUM3                                               NUMBER


       NUM       NUM2       NUM3
---------- ---------- ----------
         1          1          1
         2          2          2

тест2

SQL> desc test2;
 Name                                      Null?    Type
 ----------------------------------------- -------- ----------------------------
 NUM                                       NOT NULL NUMBER
 NUM2                                      NOT NULL NUMBER
 NUM3                                               NUMBER


       NUM       NUM2       NUM3
---------- ---------- ----------
         1          1          1
         3          1          1

Согласно книге, если заменить условие NOT IN на LEFT Outer join; производительность запроса увеличится.

Объясните план 1

SQL> select * 
       from test 
      where num NOT IN (select num 
                          from test2);

NUM      NUM2       NUM3
--- --------- ----------
2          2          2

План выполнения

----------------------------------------------------------
Plan hash value: 856752680

----------------------------------------------------------------------------
| Id  | Operation          | Name  | Rows  | Bytes | Cost (%CPU)| Time     |
----------------------------------------------------------------------------
|   0 | SELECT STATEMENT   |       |     1 |     2 |     5   (0)| 00:00:01 |
|*  1 |  FILTER            |       |       |       |            |          |
|   2 |   TABLE ACCESS FULL| TEST  |     2 |     4 |     3   (0)| 00:00:01 |
|*  3 |   TABLE ACCESS FULL| TEST2 |     2 |    26 |     2   (0)| 00:00:01 |
----------------------------------------------------------------------------

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

   1 - filter( NOT EXISTS (SELECT /*+ */ 0 FROM "TEST2" "TEST2" WHERE
              LNNVL("NUM"<>:B1)))
   3 - filter(LNNVL("NUM"<>:B1))

Поэтому я создал индексы для столбцов num обеих таблиц и переписал запрос как:

Объясните план 2

SQL> select * 
       from test 
  left join test2 on (test.num = test2.num) 
      where test2.num is null;

       NUM       NUM2       NUM3        NUM       NUM2       NUM3
---------- ---------- ---------- ---------- ---------- ----------
         2          2          2


Execution Plan
----------------------------------------------------------
Plan hash value: 1525288557

--------------------------------------------------------------------------------
| Id  | Operation                     | Name  | Rows  | Bytes | Cost (%CPU)| Tim
--------------------------------------------------------------------------------
|   0 | SELECT STATEMENT              |       |     2 |    82 |     4   (0)| 00:
|*  1 |  FILTER                       |       |       |       |            |
|   2 |   NESTED LOOPS OUTER          |       |     2 |    82 |     4   (0)| 00:
|   3 |    TABLE ACCESS FULL          | TEST  |     2 |     4 |     3   (0)| 00:
|   4 |    TABLE ACCESS BY INDEX ROWID| TEST2 |     1 |    39 |     1   (0)| 00:
|*  5 |     INDEX RANGE SCAN          | ID2   |     1 |       |     0   (0)| 00:
--------------------------------------------------------------------------------

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

   1 - filter("TEST2"."NUM" IS NULL)
   5 - access("TEST"."NUM"="TEST2"."NUM"(+))

Я явно что-то упускаю, поскольку предложенный метод оказывается более дорогим. Это связано с моим распределением данных?

Версия: Oracle 10g


person Ricko M    schedule 28.05.2011    source источник
comment
Вы разместили данные, но не информацию таблицы. Из-за разницы я склонен полагать, что сравниваемые столбцы допускают значение NULL из-за информации в этой статье   -  person OMG Ponies    schedule 28.05.2011
comment
Oracle 10g, обновление тоже под вопросом :)   -  person Ricko M    schedule 28.05.2011
comment
Ваши два запроса возвращают разные наборы результатов. Вторая версия также возвращает данные из второй таблицы. Я ожидаю, что запрос, который возвращает данные из двух таблиц, будет дороже, чем запрос, который возвращает данные только из одной. Попробуйте второй запрос с select test.* вместо select * и посмотрите, будет ли это иметь значение.   -  person APC    schedule 28.05.2011
comment
@APC Да! Это было причиной, не могли бы вы опубликовать ответ, чтобы я мог принять? Ваше здоровье!   -  person Ricko M    schedule 28.05.2011


Ответы (1)


Ваши два запроса возвращают разные наборы результатов. Вторая версия также возвращает данные из второй таблицы. Я ожидаю, что запрос, который возвращает данные из двух таблиц, будет дороже, чем запрос, который возвращает данные только из одной.

Попробуйте второй запрос с select test.* вместо select * и посмотрите, будет ли это иметь значение.

person APC    schedule 28.05.2011