Подведем итоги: нам нужно поместить приблизительно 5 миллионов строк в базу данных поставщика (Oracle). Все отлично подходит для пакетов по OracleBulkCopy
500 тыс. Строк с использованием (ODP.NET), но когда мы пытаемся масштабировать до 5M, производительность начинает снижаться, когда достигает отметки 1M, становится все медленнее по мере загрузки большего количества строк и, в конечном итоге, Тайм-аут через 3 часа или около того.
Я подозреваю, что это связано с первичным ключом на столе, но я тралял форумы Oracle и Переполнение стека для информации, и многое из того, что я читаю, противоречит этому (также, много сообщений, кажется, противоречат друг другу ) , Я надеюсь, что кто-то сможет установить рекорд по некоторым тесно связанным вопросам о процессе:
OracleBulkCopy
Использует ли класс обычную или прямую загрузку? Есть ли способ, которым я могу это подтвердить, так или иначе?Если предположить , что делает использование прямой путь загрузки: Верно ли , что Oracle автоматически устанавливает все индексы в непригодной во время загрузки и помещает их обратно в Интернете потом? Я прочитал несколько утверждений на этот счет, но, опять же, не могу подтвердить это.
Если # 2 истинно, то должно ли иметь значение, какие индексы есть в таблице, прежде чем я начну операцию массового копирования? Если так, то почему?
Относительно # 3, есть ли вообще практическая разница между массовой загрузкой с непригодным индексом и фактическим сбросом индекса перед загрузкой и его повторным созданием после этого?
Если # 2 это не правильно, или если есть некоторые оговорки я не понимающие, то он будет делать какое - либо различие в явном виде сделать индекс непригодным для использования до массовой загрузки, а затем явно восстановить его потом?
Есть ли что-то еще, кроме построения индексов, которое может привести к постепенному замедлению операции массового копирования по мере добавления большего количества записей? (Может быть, что-то делать с журналированием, хотя я ожидаю, что массовые операции не регистрируются?)
Если на самом деле нет другого способа поднять производительность, кроме как сначала сбросить PK / index, какие шаги я могу предпринять, чтобы убедиться, что индекс не исчезает полностью, т.е. если соединение с базой данных потеряно в середина процесса?
Ответы:
Еще несколько дней чтения и экспериментов, и я смог (в основном) ответить на многие из них:
Я нашел это похороненным в документации ODP.NET (по иронии судьбы не в
OracleBulkCopy
документах):Поэтому представляется , что он действительно использовать прямой путь.
Это я смог проверить, выполнив операцию массового копирования и получив свойства индекса от разработчика SQL. Индекс сделал выглядеть как в
UNUSABLE
то время как основная копия была в процессе. Тем не менее , я также обнаружил, что онOracleBulkCopy.WriteToServer
будет отказываться работать, если индекс начинается вUNUSABLE
состоянии, поэтому очевидно, что здесь происходит больше, потому что если бы это было так же просто, как отключить и перестроить индекс, то его не должно волновать начальное состояние.Это действительно имеет значение, особенно если индекс также является ограничением . Нашел этот маленький драгоценный камень в документации, указанной выше:
Документация немного неясна в отношении того, что происходит во время загрузки, особенно с первичными ключами, но совершенно точно одно - с первичным ключом он ведет себя по-разному и без него . Поскольку, к
OracleBulkCopy
счастью, вы позволите вам нарушить ограничения индекса (и перевести индекс вUNUSABLE
состояние, когда оно выполнено), я догадываюсь, что он строит индекса PK во время массового копирования , но просто не не проверки , пока позже.Я не уверен, находится ли наблюдаемая разница в самой Oracle или просто из
OracleBulkCopy
. Жюри все еще на этом.OracleBulkCopy
сгенерирует исключение, если индекс изначально находится вUNUSABLE
состоянии, так что это действительно спорный вопрос.Если здесь есть другие факторы, индексы (и особенно PK индексы) по - прежнему самое главное, как я узнал от:
Создание глобальной временной таблицы с той же схемой (с использованием
CREATE AS
), затем массовое копирование во временную таблицу и, наконец, выполнение простого старогоINSERT
из временной таблицы в реальную таблицу. Так как временная таблица не имеет индекса, массовое копирование происходит очень быстро, а финальноеINSERT
также быстро, потому что данные уже находятся в таблице (я еще не пробовал подсказку добавления, так как копия таблицы в таблицу 5M) уже занимает не более 1 минуты).Я еще не уверен в возможных последствиях (ab) использования временного табличного пространства таким образом, но пока это не доставило мне никаких проблем, и это намного безопаснее, чем альтернатива, благодаря предотвращению повреждения строк. или индексы.
Успех этого также довольно ясно демонстрирует, что проблема заключается в индексе PK, поскольку это единственное практическое различие между временной таблицей и постоянной таблицей - обе они начинались с нулевых строк во время тестов производительности.
Вывод: не пытайтесь массово копировать более 100 тыс. Строк в индексированную таблицу Oracle, используя ODP.NET. Либо удалите индекс (если он вам на самом деле не нужен), либо «предварительно загрузите» данные в другую (неиндексированную) таблицу.
источник
Delete
невозможно, потому что индекс естьUNUSABLE
. Это результат проверки ограничений, которая происходит в конце массовой копии.alter session set skip_unusable_indexes = true;
Вот статья от Oracle, которая объясняет, когда будет полезно использовать массовую вставку, а когда нет. Кроме того, имеет представление о том, что происходит на уровне базы данных.
http://docs.oracle.com/cd/B28359_01/server.111/b28319/ldr_modes.htm
источник