#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: можете ли вы разделить работу так, чтобы несколько процессов могли обрабатывать вставки одновременно?