Инструкция Oracle с несколькими вставками

#oracle #query-hints

#Oracle #запрос-подсказки

Вопрос:

В моем приложении я должен добавить много записей. Я использую следующую конструкцию:

    INSERT /*  append parallel(t1, 4) parallel(t2, 4) */ ALL
   INTO t1 (col1, col2, col3) VALUES ('val1_1', 'val1_2', 'val1_3')
   INTO t2 (col1, col2, col3) VALUES ('val2_1', 'val2_2', 'val2_3')
   INTO t2 (col1, col2, col3) VALUES ('val3_1', 'val3_2', 'val3_3')
   .
   .
   .
SELECT 1 FROM DUAL;
  

Я также использую подсказки APPEND и PARALLEL. Обратите внимание, что я вставляю данные в две разные таблицы. Кажется, что parallel игнорируется (администратор базы данных сказал мне). Итак, как я могу узнать, используется она или нет? Возможно ли использовать ПАРАЛЛЕЛЬНУЮ подсказку в такой конструкции? Эффективно ли это?

Комментарии:

1. Где подсказки в вашем заявлении? Это действительно та инструкция, которую вы используете? Что именно вы пытаетесь сделать параллельно? Есть ли у вас фактический запрос как часть вставки из нескольких таблиц или использование DUAL является просто грубым упрощением того, что вы делаете? Используете ли вы ПАРАЛЛЕЛЬНЫЙ DML?

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

3. Сколько это «много записей», несколько десятков или несколько миллионов?

4. Около 30 записей на инструкцию.

5. Все ответы очень полезны. К сожалению, я не могу выбрать все. Большое вам спасибо.

Ответ №1:

Вероятно, этого будет достаточно, чтобы заставить его работать:

 alter session enable parallel dml;
  

Вы можете проверить фактическую степень параллелизма с помощью запроса, подобного этому:

 select px_servers_executions, v$sql.*
from v$sql where lower(sql_text) like '%insert%parallel%' order by last_load_time desc;
  

Если вы все еще не получаете параллелизм, есть много возможных причин. Для начала взгляните на эти параметры:

 select * from v$parameter where name like 'parallel%'
  

Но вам, вероятно, не нужен параллелизм для вашей инструкции insert. Параллелизм сопряжен с большими накладными расходами и, как правило, полезен только в том случае, если вы имеете дело со многими тысячами или миллионами записей.

Я предполагаю, что ваша настоящая проблема — это время для разбора большой инструкции SQL. Вставки с несколькими таблицами особенно плохи. Если вы попытаетесь вставить более нескольких сотен строк, синтаксический анализ вашего запроса займет много секунд. И в зависимости от вашей версии Oracle, она просто зависнет навсегда, если вы попытаетесь использовать таблицы 501. Намного быстрее выполнять несколько запросов меньшего размера вместо одного большого запроса. Например, 5 вставок по 100 строк будут выполняться намного быстрее, чем одна вставка из 500 строк. (В общем, это полная противоположность тому, как настраивать производительность для Oracle. Это особый случай из-за ошибок, связанных с синтаксическим анализом больших инструкций SQL.)

Ответ №2:

Подсказка APPEND поддерживается только синтаксисом подзапроса инструкции INSERT, а не предложением VALUES. Если вы укажете подсказку APPEND с предложением VALUES, она будет проигнорирована и будет использоваться обычная вставка. Чтобы использовать ВСТАВКУ по прямому пути с предложением VALUES, обратитесь к «Подсказке APPEND_VALUES».

Ответ №3:

Бывают случаи, когда параллелизм отключен. В том числе из документации Oracle:

Параллелизм отключен для операций DML с таблицами, для которых вы определили триггер или ограничение ссылочной целостности.

Мне это кажется довольно большим ограничением. Есть ли у вас триггер или внешний ключ в ваших таблицах?

Ответ №4:

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

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


Обновление: Другой идеей может быть выполнение инструкций с более чем одним сеансом, эффективно реализуя параллелизм DIY. Можете ли вы спроектировать свой процесс таким образом, чтобы несколько сеансов считывали входные данные и вставляли их одновременно?

Комментарии:

1. Привет, Висент. Это невозможно. Мое приложение считывает миллионы записей, обрабатывает их и записывает результаты (консолидированные). Я попробовал несколько решений, таких как пакет для сбора записей в памяти и их записи с использованием массовой операции, но это снизило производительность (накладные расходы на вызов хранимой процедуры для каждой записи).

2. @Eduardo: можете ли вы разделить работу так, чтобы несколько процессов могли обрабатывать вставки одновременно?