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:
OracleBulkCopy
Verwendet die Klasse konventionelles oder direktes Laden? Kann ich das auf die eine oder andere Weise bestätigen?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.
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?
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?
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?
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?)
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?
Antworten:
Noch ein paar Tage Lesen und Experimentieren und ich konnte (meistens) viele dieser Fragen beantworten:
Ich fand dies in der ODP.NET-Dokumentation begraben (ironischerweise nicht in den
OracleBulkCopy
Dokumenten):Es scheint also, dass der direkte Pfad verwendet wird.
Dies konnte ich überprüfen, indem ich einen umfangreichen Kopiervorgang durchführte und die Indexeigenschaften von SQL Developer abrief. Der Index wurde angezeigt ,
UNUSABLE
während die Massenkopie ausgeführt wurde. Allerdings habe ich auch entdeckt , dassOracleBulkCopy.WriteToServer
laufen zu verweigern , wenn der Index beginnt in einemUNUSABLE
Zustand, 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.Es macht einen Unterschied, speziell wenn der Index auch eine Einschränkung ist . Fand dieses kleine Juwel in der oben verlinkten Dokumentation:
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
OracleBulkCopy
wird gerne können Sie verletzen Index Einschränkungen (und den Index in PuntUNUSABLE
Zustand , 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.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.OracleBulkCopy
wird eine Ausnahme auslösen, wenn ein Index anfänglich imUNUSABLE
Status ist, es ist also wirklich ein strittiger Punkt.Wenn da andere Faktoren sind Indizes (und insbesondere PK-Indizes) nach wie vor die wichtigsten, wie ich Folgendes herausgefunden habe:
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 KopieINSERT
ist 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.
quelle
Delete
ist nicht möglich da der index istUNUSABLE
. Dies ist ein Ergebnis der Einschränkungsprüfung, die am Ende der Massenkopie stattfindet.alter session set skip_unusable_indexes = true;
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
quelle