Що конкретно робить OracleBulkCopy і як я можу оптимізувати його ефективність?


14

Підсумовуючи особливості: нам потрібно надати приблизно 5 мільйонів рядків у базу даних постачальників (Oracle). Все ідеально підходить для партій з 500- OracleBulkCopyрядкових рядків за допомогою (ODP.NET), але коли ми намагаємося масштабувати до 5М, продуктивність починає сповільнюватися до сканування, як тільки вона потрапляє на позначку 1М, стає прогресивно повільніше, оскільки завантажується більше рядків, і врешті-решт разів через 3 години.

Я підозрюю, що це пов’язано з первинним ключем на столі, але я перебирав форуми Oracle і стек переповнення інформації та багато того, що я читаю, суперечить цьому (також багато публікацій, здається, суперечать одне одному ) . Я сподіваюся, що хтось зможе встановити рекорд на деякі тісно пов'язані питання щодо процесу:

  1. Чи використовує OracleBulkCopyклас звичайне або пряме завантаження? Чи я можу це, так чи інакше, підтвердити?

  2. Якщо припустити , що робить використання прямий шлях завантаження: Чи правда , що Oracle автоматично встановлює всі індекси в непридатною під час завантаження і поміщає їх назад в Інтернеті потім? Я прочитав кілька тверджень про це, але знову ж таки, не можу підтвердити це.

  3. Якщо №2 є істинним, то чи має бути якесь значення, які індекси є в таблиці, перш ніж я ініціюю операцію масового копіювання? Якщо так, то чому?

  4. Що стосується №3, чи є взагалі якась практична різниця між масовим завантаженням з непридатним індексом порівняно з фактичним скиданням індексу перед завантаженням та відтворенням його після цього?

  5. Якщо # 2 це НЕ правильно, або якщо є деякі застереження я не розуміють, то він буде робити яке - або відмінність в явному вигляді зробити індекс непридатним для використання до масової завантаження, а потім явно відновити його потім?

  6. Чи є щось інше, крім збірки індексу, що могло б призвести до того, що операція масової копії поступово повільніше зростає, оскільки додається все більше записів? (Можливо, щось пов'язане з веденням журналу, хоча я б очікував, що масові операції не реєструються?)

  7. Якщо насправді немає іншого способу підняти продуктивність, щоб опустити спочатку PK / індекс, то які дії можна зробити, щоб переконатися, що індекс не зникне повністю, тобто якщо втрачено з'єднання з базою даних середина процесу?


Бічна примітка: Копіювані дані вже впорядковані у відповідності з ПК, який є єдиним індексом у таблиці.
Aaronaught

Ви використовуєте DataReader для читання даних з джерела?
bernd_k

@bernd_k: Ні, завантажується повністю з пам'яті. Це точно не джерело.
Aaronaught

Відповіді:


13

Ще кілька днів читання та експериментів, і я зміг (в основному) відповісти на багато з них:

  1. Я знайшов це захопленим у документації на ODP.NET (за іронією долі не у OracleBulkCopyдокументах):

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

    Тому представляється , що він дійсно використовувати прямий шлях.

  2. Це мені вдалося перевірити, виконавши велику операцію масової копії та отримавши властивості індексу від SQL Developer. Індекс зробив виглядати як в UNUSABLEтой час як основна копія була в процесі. Однак я також виявив, що OracleBulkCopy.WriteToServerбуде відмовлятись від запуску, якщо індекс запуститься у UNUSABLEстані, тому явно тут відбувається більше, адже якби це було так просто, як відключення та відновлення індексу, тоді він не повинен піклуватися про початковий стан.

  3. Це має особливе значення, якщо індекс також є обмеженням . Знайдено цей маленький дорогоцінний камінь у документації, зв'язаній вище:

    Увімкнено обмеження
    Під час масової копії Oracle такі обмеження автоматично вмикаються за замовчуванням:

    • NOT NULL
    • UNIQUE
    • PRIMARY KEY (унікальні обмеження на стовпці, що не ставляться до нуля)

    NOT NULLобмеження перевіряються на час створення масиву стовпців. Будь-який рядок, що порушує NOT NULLобмеження, відхиляється.

    UNIQUEобмеження перевіряються, коли індекси відбудовуються наприкінці завантаження. Індекс залишається в індексі Непридатний стан, якщо він порушує UNIQUEобмеження.

    Документація трохи туманно про те , що відбувається під час завантаження, особливо з первинними ключами, але одна річ абсолютно впевнений - він веде себе по- різному з первинним ключем VS. без одного. Оскільки OracleBulkCopyзаповіт із задоволенням дозволить вам порушити обмеження індексу (і перевести індекс у UNUSABLEстан, коли це буде зроблено), моя думка полягає в тому, що він будує індекс PK під час масової копії, але просто не перевіряє його до цього.

  4. Я не впевнений, чи спостерігається різниця в самому Oracle чи просто химерність OracleBulkCopy. Журі все ще не в цьому.

  5. OracleBulkCopyвикине виняток, якщо індекс спочатку знаходиться в UNUSABLEстані, тож це дійсно суперечливий момент.

  6. Якщо є інші фактори, індекси (особливо PK-індекси) все ще є найважливішими, як я з'ясував:

  7. Створення глобальної тимчасової таблиці з тією ж схемою (за допомогою CREATE AS), потім масове копіювання у тимчасову таблицю і, нарешті, просте старе INSERTз таблиці темп у реальну таблицю. Оскільки в таблиці темпів немає індексу, об'ємна копія відбувається дуже швидко, а фінальна INSERT- також швидка, оскільки дані вже є в таблиці (я ще не пробував підказку щодо додавання, оскільки копія таблиці 5 до рядка в рядку вже займає менше 1 хвилини).

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

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

Висновок: Не турбуйтеся намагатися скопіювати копіювання більше ніж близько 100 тис. Рядків у індексовану таблицю Oracle за допомогою ODP.NET. Або опустіть індекс (якщо він вам фактично не потрібен), або "попередньо завантажте" дані в іншу (неіндексовану) таблицю.


Я не впевнений у перевірці обмежень первинного ключа. Я подумав 2 рази вставити ті самі дані в таблицю Oracle і Select * показує 2 повторюваних рядки. У такому стані Видалити неможливо, але таблиця скорочення допомагає повернутися до чистого стану.
bernd_k

@bernd_k: Deleteнеможливо, оскільки індекс є UNUSABLE. Це результат перевірки обмеження, яка відбувається в кінці об'ємної копії.
Aaronaught

У мене працює скрипт PowerShell, який викликає групову копію в базу даних Oracle із зчитувача даних SQL Server, усі цільові таблиці з первинними ключами, і у мене немає проблем із таблицями до 205278 рядків. Але я дуже обережний, щоб спочатку заповнити основні таблиці, перш ніж заповнити таблиці деталей. Я не видалив жоден інший індекс із таблиці, і у мене немає проблем, коли таблиці спочатку порожні.
bernd_k

@bernd_k: Так, у мене в цьому обсязі не було занадто багато проблем (див. мій останній абзац). Це коли ви потрапляєте у мільйони, це стає жахливим. Також може бути різниця, якщо ви опустіть таблицю десь після кожної масової копії (ця не видаляється, вона додається, і ви знаєте, як індекси повільніше стають більшими).
Aaronaught

Можливо, це допоможе, коли ти робишalter session set skip_unusable_indexes = true;
Wernfried Domscheit

1

Ось стаття від Oracle, в якій пояснюється, коли буде корисно використовувати об'ємні вставки або коли ні. Також має уявлення про те, що відбувається на рівні бази даних.

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


3
Посилання мають тенденцію до гниття; ви можете включити у відповідь відповідну інформацію за посиланням.
мустаччо
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.