Что конкретно делает OracleBulkCopy и как я могу оптимизировать его производительность?

14

Подведем итоги: нам нужно поместить приблизительно 5 миллионов строк в базу данных поставщика (Oracle). Все отлично подходит для пакетов по OracleBulkCopy500 тыс. Строк с использованием (ODP.NET), но когда мы пытаемся масштабировать до 5M, производительность начинает снижаться, когда достигает отметки 1M, становится все медленнее по мере загрузки большего количества строк и, в конечном итоге, Тайм-аут через 3 часа или около того.

Я подозреваю, что это связано с первичным ключом на столе, но я тралял форумы Oracle и Переполнение стека для информации, и многое из того, что я читаю, противоречит этому (также, много сообщений, кажется, противоречат друг другу ) , Я надеюсь, что кто-то сможет установить рекорд по некоторым тесно связанным вопросам о процессе:

  1. OracleBulkCopyИспользует ли класс обычную или прямую загрузку? Есть ли способ, которым я могу это подтвердить, так или иначе?

  2. Если предположить , что делает использование прямой путь загрузки: Верно ли , что Oracle автоматически устанавливает все индексы в непригодной во время загрузки и помещает их обратно в Интернете потом? Я прочитал несколько утверждений на этот счет, но, опять же, не могу подтвердить это.

  3. Если # 2 истинно, то должно ли иметь значение, какие индексы есть в таблице, прежде чем я начну операцию массового копирования? Если так, то почему?

  4. Относительно # 3, есть ли вообще практическая разница между массовой загрузкой с непригодным индексом и фактическим сбросом индекса перед загрузкой и его повторным созданием после этого?

  5. Если # 2 это не правильно, или если есть некоторые оговорки я не понимающие, то он будет делать какое - либо различие в явном виде сделать индекс непригодным для использования до массовой загрузки, а затем явно восстановить его потом?

  6. Есть ли что-то еще, кроме построения индексов, которое может привести к постепенному замедлению операции массового копирования по мере добавления большего количества записей? (Может быть, что-то делать с журналированием, хотя я ожидаю, что массовые операции не регистрируются?)

  7. Если на самом деле нет другого способа поднять производительность, кроме как сначала сбросить PK / index, какие шаги я могу предпринять, чтобы убедиться, что индекс не исчезает полностью, т.е. если соединение с базой данных потеряно в середина процесса?

Aaronaught
источник
Примечание: Копируемые данные уже отсортированы в соответствии с PK, который является единственным индексом в таблице.
Aaronaught
Вы используете DataReader для чтения данных из источника?
bernd_k
@bernd_k: Нет, загрузка полностью из памяти. Проблема не в источнике.
Ааронаут

Ответы:

13

Еще несколько дней чтения и экспериментов, и я смог (в основном) ответить на многие из них:

  1. Я нашел это похороненным в документации ODP.NET (по иронии судьбы не в OracleBulkCopyдокументах):

    Функция группового копирования ODP.NET использует подход с прямой загрузкой пути, который похож, но не совпадает с Oracle SQL * Loader. Использование прямой загрузки по пути быстрее, чем обычная загрузка (с использованием обычных операторов SQL INSERT).

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

  2. Это я смог проверить, выполнив операцию массового копирования и получив свойства индекса от разработчика SQL. Индекс сделал выглядеть как в UNUSABLEто время как основная копия была в процессе. Тем не менее , я также обнаружил, что он OracleBulkCopy.WriteToServerбудет отказываться работать, если индекс начинается в UNUSABLEсостоянии, поэтому очевидно, что здесь происходит больше, потому что если бы это было так же просто, как отключить и перестроить индекс, то его не должно волновать начальное состояние.

  3. Это действительно имеет значение, особенно если индекс также является ограничением . Нашел этот маленький драгоценный камень в документации, указанной выше:

    Включенные ограничения
    Во время массового копирования Oracle по умолчанию автоматически включаются следующие ограничения:

    • NOT NULL
    • UNIQUE
    • PRIMARY KEY (уникальные ограничения на ненулевые столбцы)

    NOT NULLограничения проверяются во время сборки массива столбцов. Любая строка, которая нарушает NOT NULLограничение, отклоняется.

    UNIQUEограничения проверяются, когда индексы перестраиваются в конце загрузки. Индекс остается в состоянии «Неиспользуемый индекс», если он нарушает UNIQUEограничение.

    Документация немного неясна в отношении того, что происходит во время загрузки, особенно с первичными ключами, но совершенно точно одно - с первичным ключом он ведет себя по-разному и без него . Поскольку, к OracleBulkCopyсчастью, вы позволите вам нарушить ограничения индекса (и перевести индекс в UNUSABLEсостояние, когда оно выполнено), я догадываюсь, что он строит индекса PK во время массового копирования , но просто не не проверки , пока позже.

  4. Я не уверен, находится ли наблюдаемая разница в самой Oracle или просто из OracleBulkCopy . Жюри все еще на этом.

  5. OracleBulkCopy сгенерирует исключение, если индекс изначально находится в UNUSABLE состоянии, так что это действительно спорный вопрос.

  6. Если здесь есть другие факторы, индексы (и особенно PK индексы) по - прежнему самое главное, как я узнал от:

  7. Создание глобальной временной таблицы с той же схемой (с использованием CREATE AS), затем массовое копирование во временную таблицу и, наконец, выполнение простого старогоINSERT из временной таблицы в реальную таблицу. Так как временная таблица не имеет индекса, массовое копирование происходит очень быстро, а финальное INSERTтакже быстро, потому что данные уже находятся в таблице (я еще не пробовал подсказку добавления, так как копия таблицы в таблицу 5M) уже занимает не более 1 минуты).

    Я еще не уверен в возможных последствиях (ab) использования временного табличного пространства таким образом, но пока это не доставило мне никаких проблем, и это намного безопаснее, чем альтернатива, благодаря предотвращению повреждения строк. или индексы.

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

Вывод: не пытайтесь массово копировать более 100 тыс. Строк в индексированную таблицу Oracle, используя ODP.NET. Либо удалите индекс (если он вам на самом деле не нужен), либо «предварительно загрузите» данные в другую (неиндексированную) таблицу.

Aaronaught
источник
Я не уверен насчет проверки ограничений первичного ключа. Я дважды вставил одни и те же данные в таблицу Oracle, и Select * показывает 2 дублированных строки. В этом состоянии удаление невозможно, но усеченная таблица помогает вернуться в чистое состояние.
bernd_k
@bernd_k: Deleteневозможно, потому что индекс есть UNUSABLE. Это результат проверки ограничений, которая происходит в конце массовой копии.
Aaronaught
У меня запущен сценарий PowerShell, вызывающий массовую копию в базу данных Oracle из устройства чтения данных SQL Server, все целевые таблицы с первичными ключами, и у меня нет проблем с таблицами до 205278 строк. Но я очень осторожен, чтобы сначала заполнить основные таблицы, прежде чем заполнять таблицы с подробностями. Я не удалил никаких других индексов в таблице, и у меня нет проблем, когда таблицы изначально пусты.
bernd_k
@bernd_k: Да, у меня не было слишком много проблем на этом томе (см. мой последний абзац). Когда вы достигаете миллионов, это становится ужасным. Также может быть разница, если вы очищаете таблицу через некоторое время после каждой массовой копии (эта не очищается, к ней добавляются, и вы знаете, как индексы замедляются по мере их увеличения).
Ааронаут
Может быть, это помогает, когда вы делаетеalter session set skip_unusable_indexes = true;
Wernfried Domscheit
1

Вот статья от Oracle, которая объясняет, когда будет полезно использовать массовую вставку, а когда нет. Кроме того, имеет представление о том, что происходит на уровне базы данных.

http://docs.oracle.com/cd/B28359_01/server.111/b28319/ldr_modes.htm

SmartCoder
источник
3
Ссылки имеют тенденцию гнить; Вы можете включить соответствующую информацию из ссылки в свой ответ.
Мустаччо