Was genau macht OracleBulkCopy und wie kann ich seine Leistung optimieren?

14

Um die Besonderheiten zusammenzufassen: Wir müssen ungefähr 5 Millionen Zeilen in einer Vendor-Datenbank (Oracle) bereitstellen. Bei Stapeln von 500.000 Zeilen mit OracleBulkCopy(ODP.NET) funktioniert alles einwandfrei. Wenn wir jedoch versuchen, auf 5 Millionen zu skalieren, verlangsamt sich die Leistung, sobald die 1-Millionen-Marke erreicht ist, und wird allmählich langsamer, je mehr Zeilen geladen werden Zeitüberschreitung nach ca. 3 Stunden.

Ich vermute , dass es im Zusammenhang mit einem Primärschlüssel auf dem Tisch, aber ich habe für Informationen über die Oracle - Foren und Stack - Überlaufes wurde Schleppe und eine Menge von dem, was ich bin im Widerspruch zu lesen , die (auch viele Beiträge zu widersprechen scheinen sie ) . Ich hoffe, dass jemand die Aufzeichnungen in Bezug auf einige eng verwandte Fragen zum Prozess klarstellen kann:

  1. OracleBulkCopyVerwendet die Klasse konventionelles oder direktes Laden? Kann ich das auf die eine oder andere Weise bestätigen?

  2. Vorausgesetzt, es wird direkt geladen: Stimmt es, dass Oracle alle Indizes während des Ladevorgangs automatisch auf unbrauchbar setzt und sie anschließend wieder online stellt? Ich habe mehrere Aussagen zu diesem Zweck gelesen, kann dies aber nicht bestätigen.

  3. Wenn # 2 wahr ist, sollte es dann einen Unterschied machen, welche Indizes in der Tabelle vorhanden sind, bevor ich einen Massenkopiervorgang einleite? Wenn ja warum?

  4. Gibt es in Bezug auf # 3 im Allgemeinen einen praktischen Unterschied zwischen dem Massenladen mit einem nicht verwendbaren Index und dem tatsächlichen Löschen des Index vor dem Laden und dem anschließenden erneuten Erstellen des Index?

  5. Wenn # 2 nicht korrekt ist oder wenn ich einige Einschränkungen nicht verstehe, macht es dann einen Unterschied , den Index vor dem Massenladen explizit unbrauchbar zu machen und ihn anschließend explizit neu zu erstellen?

  6. Gibt es etwas anderes als Indexerstellungen, das dazu führen kann, dass ein Massenkopiervorgang mit dem Hinzufügen von immer mehr Datensätzen immer langsamer wird? (Vielleicht etwas mit der Protokollierung zu tun, obwohl ich davon ausgehen würde, dass Massenvorgänge nicht protokolliert werden?)

  7. Wenn es wirklich keine andere Möglichkeit gibt, die Leistung zu verbessern, als zuerst den PK / Index zu löschen, welche Schritte kann ich unternehmen, um sicherzustellen, dass der Index nicht vollständig verschwindet, dh wenn die Verbindung zur Datenbank verloren geht mitten im Prozess?

Aaronaught
quelle
Randnotiz: Die Daten, die kopiert werden, sind bereits in sortierter Reihenfolge nach der PK aufgeführt, die der einzige Index in der Tabelle ist.
Aaronaught
Verwenden Sie einen DataReader, um die Daten aus der Quelle zu lesen?
bernd_k
@bernd_k: Nein, vollständig aus dem Speicher laden. Es ist definitiv nicht die Quelle, die das Problem ist.
Aaronaught

Antworten:

13

Noch ein paar Tage Lesen und Experimentieren und ich konnte (meistens) viele dieser Fragen beantworten:

  1. Ich fand dies in der ODP.NET-Dokumentation begraben (ironischerweise nicht in den OracleBulkCopyDokumenten):

    Die Massenkopierfunktion von ODP.NET verwendet einen direkten Pfadladeansatz, der dem von Oracle SQL * Loader ähnelt, jedoch nicht mit diesem identisch ist. Das direkte Laden von Pfaden ist schneller als das herkömmliche Laden (mit herkömmlichen SQL- INSERTAnweisungen).

    Es scheint also, dass der direkte Pfad verwendet wird.

  2. Dies konnte ich überprüfen, indem ich einen umfangreichen Kopiervorgang durchführte und die Indexeigenschaften von SQL Developer abrief. Der Index wurde angezeigt , UNUSABLEwährend die Massenkopie ausgeführt wurde. Allerdings habe ich auch entdeckt , dass OracleBulkCopy.WriteToServerlaufen zu verweigern , wenn der Index beginnt in einem UNUSABLEZustand, so klar ist es mehr hier los ist , denn wenn es so einfach wäre , wie zu deaktivieren und den Wiederaufbau der Index dann sollte es nicht um Anfangszustand kümmern.

  3. Es macht einen Unterschied, speziell wenn der Index auch eine Einschränkung ist . Fand dieses kleine Juwel in der oben verlinkten Dokumentation:

    Aktivierte Einschränkungen
    Während einer Oracle-Massenkopie werden die folgenden Einschränkungen standardmäßig automatisch aktiviert:

    • NOT NULL
    • UNIQUE
    • PRIMARY KEY (Unique-Constraints für Nicht-Null-Spalten)

    NOT NULLEinschränkungen werden zur Erstellungszeit des Spaltenarrays überprüft. Jede Zeile, die die NOT NULLEinschränkung verletzt , wird abgelehnt.

    UNIQUEEinschränkungen werden überprüft, wenn Indizes am Ende des Ladevorgangs neu erstellt werden. Der Index wird in einem nicht verwendbaren Indexzustand belassen, wenn eine UNIQUEEinschränkung verletzt wird .

    Die Dokumentation ist ein wenig unklar, was während des Ladevorgangs passiert , insbesondere bei Primärschlüsseln. Eines ist jedoch absolut sicher - es verhält sich bei einem Primärschlüssel anders als bei einem Schlüssel ohne . Da das OracleBulkCopywird gerne können Sie verletzen Index Einschränkungen (und den Index in Punt UNUSABLEZustand , wenn es fertig ist), ist meine Vermutung , dass es den Aufbau des PK - Index während des Massenkopier aber einfach nicht die Validierung , bis später.

  4. Ich bin mir nicht sicher, ob der beobachtete Unterschied in Oracle selbst liegt oder nur eine Eigenart der OracleBulkCopy. Die Jury ist immer noch nicht da.

  5. OracleBulkCopywird eine Ausnahme auslösen, wenn ein Index anfänglich im UNUSABLEStatus ist, es ist also wirklich ein strittiger Punkt.

  6. Wenn da andere Faktoren sind Indizes (und insbesondere PK-Indizes) nach wie vor die wichtigsten, wie ich Folgendes herausgefunden habe:

  7. Erstellen einer globalen temporären Tabelle mit demselben Schema (mithilfe von CREATE AS), Massenkopieren in die temporäre Tabelle und schließlich Ausführen einer einfachen alten TabelleINSERT Tabelle aus der temporären Tabelle in die reale Tabelle. Da die temporäre Tabelle keinen Index hat, erfolgt die Massenkopie sehr schnell, und die endgültige Kopie INSERTist auch schnell, da sich die Daten bereits in einer Tabelle befinden dauert schon weniger als 1 Minute).

    Ich bin mir noch nicht sicher, welche Konsequenzen es haben kann, wenn (ab) den temporären Tabellenbereich auf diese Weise verwendet wird, aber bisher hat es mir keine Probleme bereitet, und es ist viel sicherer als die Alternative, um eine Beschädigung der Zeilen zu verhindern oder Indizes.

    Der Erfolg zeigt auch ziemlich deutlich, dass der PK-Index das Problem ist, da dies der einzige praktische Unterschied zwischen der temporären Tabelle und der permanenten Tabelle ist - beide wurden während der Leistungstests mit Nullzeilen gestartet.

Fazit: Versuchen Sie nicht, mit ODP.NET mehr als 100.000 Zeilen in eine indizierte Oracle-Tabelle zu kopieren. Löschen Sie entweder den Index (falls Sie ihn nicht wirklich benötigen) oder "laden" Sie die Daten in eine andere (nicht indizierte) Tabelle.

Aaronaught
quelle
Ich bin mir nicht sicher, ob ich die Einschränkungen für Primärschlüssel überprüfen soll. Ich habe die gleichen Daten 2-mal in eine Oracle-Tabelle eingefügt und Select * zeigt 2 die duplizierten Zeilen. In diesem Zustand ist das Löschen nicht möglich, aber das Abschneiden der Tabelle hilft dabei, einen sauberen Zustand wiederherzustellen.
bernd_k
@bernd_k: Deleteist nicht möglich da der index ist UNUSABLE. Dies ist ein Ergebnis der Einschränkungsprüfung, die am Ende der Massenkopie stattfindet.
Aaronaught
Ich habe ein PowerShell-Skript ausgeführt, das Bulkcopy in einer Oracle-Datenbank von einem SQL Server-Datenleser aufruft, alle Zieltabellen mit Primärschlüsseln und ich habe keine Probleme mit Tabellen mit bis zu 205278 Zeilen. Aber ich bin sehr vorsichtig, bevor ich die Detailtabellen ausfülle. Ich habe keinen der anderen Indizes für die Tabelle entfernt und habe keine Probleme, wenn die Tabellen anfangs leer sind.
bernd_k
@bernd_k: Ja, ich hatte auch bei dieser Lautstärke nicht allzu viele Probleme (siehe meinen letzten Absatz). Es ist, wenn Sie in die Millionen greifen, dass es schrecklich wird. Es kann auch einen Unterschied geben, wenn Sie die Tabelle irgendwann nach jeder Massenkopie leeren (diese wird nicht geleert, sie wird angehängt und Sie wissen, wie die Indizes langsamer werden, wenn sie größer werden).
Aaronaught
Vielleicht hilft es, wenn Sie einenalter session set skip_unusable_indexes = true;
Wernfried Domscheit
1

Hier ist ein Artikel von Oracle, in dem erläutert wird, wann die Verwendung von Bulk Insert von Vorteil ist oder wann nicht. Hat auch einen Einblick darüber, was auf Datenbankebene passiert.

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

SmartCoder
quelle
3
Links neigen dazu zu faulen; Möglicherweise möchten Sie relevante Informationen aus dem Link in Ihre Antwort aufnehmen.
Mustaccio