Подзапрос SQL и соединения, дающие одинаковые или разные результаты (оракул)

Я работаю над оптимизацией запросов из-за огромного количества данных в Oracle.

Есть один запрос, подобный этому.

С подзапросом:

SELECT
  STG.ID1,
  STG.ID2
FROM (SELECT 
        DISTINCT
        H1.ID1,
        H2.ID2
      FROM T_STGDV STG
      INNER JOIN T_HUB1 H1 ON STG.BK1 = H1.BK1
      INNER JOIN T_HUB2 H2 ON STG.BK2 = H2.BK2 ) STG
LEFT OUTER JOIN T_LINK L ON  L.ID1 = STG.ID1 AND L.ID2 = STG.ID2
WHERE L.IDL IS NULL;

Я делаю эту оптимизацию:

SELECT 
  DISTINCT
  H1.ID1,
  H2.ID2
FROM T_STGDV STG
INNER JOIN T_HUB1 H1 ON STG.BK1 = H1.BK1
INNER JOIN T_HUB2 H2 ON STG.BK2 = H2.BK2 
LEFT OUTER JOIN T_LINK L ON L.ID1 = H1.ID1 AND L.ID2 = H2.ID2
WHERE L.IDL IS NULL;

Я хочу знать, будет ли результат таким же, поведение будет таким же.

Я сделал несколько тестов, я не нашел разницы, но, может быть, я пропустил какой-то тест?

Есть идеи, в чем может быть разница между этими запросами?

Благодарю.

Некоторые детали, план объяснения для этих таблиц тестирования (стоимость не соответствует реальным таблицам)

Первый запрос:

Plan hash value: 2680307749

-----------------------------------------------------------------------------------
| Id  | Operation               | Name    | Rows  | Bytes | Cost (%CPU)| Time     |
-----------------------------------------------------------------------------------
|   0 | SELECT STATEMENT        |         |     1 |    65 |    11  (28)| 00:00:01 |
|*  1 |  FILTER                 |         |       |       |            |          |
|*  2 |   HASH JOIN OUTER       |         |     1 |    65 |    11  (28)| 00:00:01 |
|   3 |    VIEW                 |         |     1 |    26 |     8  (25)| 00:00:01 |
|   4 |     HASH UNIQUE         |         |     1 |   134 |     8  (25)| 00:00:01 |
|*  5 |      HASH JOIN          |         |     1 |   134 |     7  (15)| 00:00:01 |
|*  6 |       HASH JOIN         |         |     1 |    94 |     5  (20)| 00:00:01 |
|   7 |        TABLE ACCESS FULL| T_STGDV |     1 |    54 |     2   (0)| 00:00:01 |
|   8 |        TABLE ACCESS FULL| T_HUB1  |     2 |    80 |     2   (0)| 00:00:01 |
|   9 |       TABLE ACCESS FULL | T_HUB2  |     2 |    80 |     2   (0)| 00:00:01 |
|  10 |    TABLE ACCESS FULL    | T_LINK  |     3 |   117 |     2   (0)| 00:00:01 |
-----------------------------------------------------------------------------------

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

   1 - filter("L"."IDL" IS NULL)
   2 - access("L"."ID2"(+)="STG"."ID2" AND "L"."ID1"(+)="STG"."ID1")
   5 - access("STG"."BK2"="H2"."BK2")
   6 - access("STG"."BK1"="H1"."BK1")

Note
-----
   - dynamic sampling used for this statement (level=2)

второй запрос

Plan hash value: 2149614538

-----------------------------------------------------------------------------------
| Id  | Operation               | Name    | Rows  | Bytes | Cost (%CPU)| Time     |
-----------------------------------------------------------------------------------
|   0 | SELECT STATEMENT        |         |     1 |    65 |    11  (28)| 00:00:01 |
|   1 |  HASH UNIQUE            |         |     1 |    65 |    11  (28)| 00:00:01 |
|*  2 |   FILTER                |         |       |       |            |          |
|*  3 |    HASH JOIN OUTER      |         |     1 |    65 |    10  (20)| 00:00:01 |
|   4 |     VIEW                |         |     1 |    26 |     7  (15)| 00:00:01 |
|*  5 |      HASH JOIN          |         |     1 |   134 |     7  (15)| 00:00:01 |
|*  6 |       HASH JOIN         |         |     1 |    94 |     5  (20)| 00:00:01 |
|   7 |        TABLE ACCESS FULL| T_STGDV |     1 |    54 |     2   (0)| 00:00:01 |
|   8 |        TABLE ACCESS FULL| T_HUB1  |     2 |    80 |     2   (0)| 00:00:01 |
|   9 |       TABLE ACCESS FULL | T_HUB2  |     2 |    80 |     2   (0)| 00:00:01 |
|  10 |     TABLE ACCESS FULL   | T_LINK  |     3 |   117 |     2   (0)| 00:00:01 |
-----------------------------------------------------------------------------------

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

   2 - filter("L"."IDL" IS NULL)
   3 - access("L"."ID2"(+)="H2"."ID2" AND "L"."ID1"(+)="H1"."ID1")
   5 - access("STG"."BK2"="H2"."BK2")
   6 - access("STG"."BK1"="H1"."BK1")

Note
-----
   - dynamic sampling used for this statement (level=2)

4 ответа

Запросы выглядят эквивалентно мне, из-за where пункт.

Без where пункт они не эквивалентны. Дубликаты в t_link (относительно join ключи) приведет к дублированию строк. Тем не менее, вы не ищете совпадений, так что это не проблема. Когда нет совпадения, две версии должны быть эквивалентны.

После тестирования там дают тот же результат. И второй более эффективен.

В этом может быть разница: посмотрите на эти строки в ваших планах выполнения:

2 - access("L"."ID2"(+)="STG"."ID2" AND "L"."ID1"(+)="STG"."ID1")

а также

3 - access("L"."ID2"(+)="H2"."ID2" AND "L"."ID1"(+)="H1"."ID1")

STG это временная таблица, созданная Oracle для продолжительности запроса (эта неопределенность между T_STGDV псевдоним и псевдоним подзапроса были единственной причиной переписать запрос). И эта временная таблица, конечно, не индексируется. После вашего рефакторинга оптимизатор Oracle начинает присоединяться T_LINK с H1 а также H2 вместо временной таблицы, что позволяет ей использовать индексы, построенные на этих таблицах, что дает увеличение скорости в 20 раз.

Если вы хотите проверить их с вашим текущим набором данных, вы можете использовать минус.

запрос 1 МИНУС запрос 2

Если отображаются какие-либо результаты, они не совпадают.

Вы должны перевернуть их, чтобы попробовать другой путь тоже...

запрос 2 МИНУС запрос 1

Если оба теста не возвращают записей, запросы оказывают одинаковое влияние на ваш текущий набор данных.

Другие вопросы по тегам