Как улучшить производительность соединения двух таблиц SCD2 в Oracle SQL - PullRequest
3 голосов
/ 18 мая 2019

У меня есть две таблицы, обе с использованием valid to и valid from logic. Таблица 1 выглядит так:

ID | VALID_FROM | VALID_TO 
1  | 01.01.2000 | 04.01.2000
1  | 04.01.2000 | 16.01.2000
1  | 16.01.2000 | 17.01.2000
1  | 17.01.2000 | 19.01.2000
2  | 03.02.2001 | 04.04.2001
2  | 04.04.2001 | 14.03.2001
2  | 14.04.2001 | 18.03.2001

в то время как таблица 2 выглядит следующим образом:

ID | VAR | VALID_FROM | VALID_TO 
1  |  3  | 01.01.2000 | 17.01.2000
1  |  2  | 17.01.2000 | 19.01.2000
2  |  4  | 03.02.2001 | 14.03.2001
  • Таблица 1 имеет 132 195 791 строк, а таблица 2 - 16 964 846.
  • Действительный от и действительный на сегодняшний день любого наблюдения в таблице 1 находится в пределах одного или более действительных от действительных до окон, показанных в таблице 2.
  • Я создал первичные ключи для них обоих по ID и VALID_FROM
  • Я хочу сделать внутреннее соединение, например:
    select t1.*, 
           t2.var 
      from t1 t1
inner join t2 t2
        on t1.id = t2.id
       and t1.valid_from >= t2.valid_from
       and t1.valid_to <= t2.valid_to;

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

EDIT

Очевидно, что предоставленная мною информация была ниже, чем обычно здесь, на платформе.

  • Я использую Oracle Database 12c Enterprise Edition
  • Пример, который я привел, был иллюстративным для более серьезной проблемы. я Я обеспокоен объединением информации из разных таблиц с разные даты valid_from / valid_to. Для этого я создал сетку сначала с разными значениями в valid_from и valid_to переменные всех соответствующих таблиц. Эта сетка - то, что я упоминаю здесь к таблице 1.
  • Результаты плана выполнения (я настроил имена столбцов и таблиц в соответствии с терминологией, использованной в моем иллюстративном примере):
    --------------------------------------------------------------------------------------
    | Id  | Operation          | Name    | Rows  | Bytes |TempSpc| Cost (%CPU)| Time     |
    --------------------------------------------------------------------------------------
    |   0 | SELECT STATEMENT   |         |   465M|    23G|       |   435K  (3)| 00:00:18 |
    |*  1 |  HASH JOIN         |         |   465M|    23G|   695M|   435K  (3)| 00:00:18 |
    |   2 |   TABLE ACCESS FULL| TABLE2 |    16M|   501M|       | 22961   (2)| 00:00:01 |
    |   3 |   TABLE ACCESS FULL| TABLE1 |   132M|  3025M|       |   145K  (2)| 00:00:06 |
    --------------------------------------------------------------------------------------

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

       1 - SEL$58A6D7F6
       2 - SEL$58A6D7F6 / T2@SEL$1
       3 - SEL$58A6D7F6 / T1@SEL$1

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

       1 - access("T1"."ID"="T2"."ID")
           filter("T1"."VALID_TO"<="T2"."VALID_TO" AND 
                  "T1"."VALID_FROM">="T2"."VALID_FROM")

    Column Projection Information (identified by operation id):
    -----------------------------------------------------------

       1 - (#keys=1) "T2"."ID"[VARCHAR2,20], 
           "T1"."ID"[VARCHAR2,20], "T1"."VALID_TO"[DATE,7], 
           "T2"."VAR"[VARCHAR2,20], "T2"."VALID_FROM"[DATE,7], 
           "T2"."VALID_TO"[DATE,7], "T1"."ID"[VARCHAR2,20], 
           "T1"."VALID_FROM"[DATE,7], "T1"."VALID_TO"[DATE,7], "T1"."VALID_FROM"[DATE,7]
       2 - "T2"."ID"[VARCHAR2,20], 
           "T2"."VAR"[VARCHAR2,20], "T2"."VALID_FROM"[DATE,7], 
           "T2"."VALID_TO"[DATE,7]
       3 - "T1"."ID"[VARCHAR2,20], "T1"."VALID_FROM"[DATE,7], 
           "T1"."VALID_TO"[DATE,7]

    Note
    -----
       - this is an adaptive plan

1 Ответ

1 голос
/ 19 мая 2019

Хорошей практикой является сначала спросить: что ожидается от запроса?

Основываясь на предикате WHERE, кажется, вас интересуют все версии из таблицы 2, которые включено в интервал действия таблицы1.Это может быть намерением, но чаще всего вам нужны все версии, которые пересекаются между таблицами.

Второй аспект: вам нужно увидеть несколько первых строк или все строки из объединения.

Если вы хотите видеть только несколько результатов, просто добавьте AND t1.ID = nnnn к предложению WHERE, чтобы ограничить его некоторым примером ID.Если у вас есть правильные индексы (и у вас нет большого количества строк с этим идентификатором), вы получите результат быстро, как только NESTED LOOP объединение вступит в силу.

Чтобы выполнить полноерезультат, вы должны рассмотреть все строки из обеих таблиц.Ни один индекс не поможет вам выбрать все строки в таблице - вот лучший выбор FULL TABLE SCAN .

Для объединения больших наборов строк лучший подход - HASH JOIN.NESTED LOOPS (который вы, вероятно, используете сейчас) быстро соединяют несколько строк, но зависает на больших наборах строк.

Меньшая таблица (table2) в памяти красная (надеюсь) какхеш-таблица.Таблица большего размера (table1) проверена против этой хеш-таблицы для выполнения объединения.

Это план выполнения, который вы должны искать

-----------------------------------------------------------------------------------
| Id  | Operation          | Name | Rows  | Bytes |TempSpc| Cost (%CPU)| Time     |
-----------------------------------------------------------------------------------
|   0 | SELECT STATEMENT   |      |    10T|   399T|       |   190M(100)| 02:03:47 |
|*  1 |  HASH JOIN         |      |    10T|   399T|   550M|   190M(100)| 02:03:47 |
|   2 |   TABLE ACCESS FULL| SCD2 |    16M|   355M|       |    39  (93)| 00:00:01 |
|   3 |   TABLE ACCESS FULL| SCD1 |   132M|  2395M|       |   211  (99)| 00:00:01 |
-----------------------------------------------------------------------------------

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

   1 - access("T1"."ID"="T2"."ID")
       filter("T1"."VALID_FROM">="T2"."VALID_FROM" AND 
              "T1"."VALID_TO"<="T2"."VALID_TO")

При условии, что вы находитесь нав базе данных enterprise это должно пройти от days до hours .Далее вы можете развернуть параллельный параметр , чтобы увеличить скорость.

Удачи!

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...