Oracle
 sql >> Datenbank >  >> RDS >> Oracle

INSERT von 10 Millionen Abfragen unter 10 Minuten in Oracle?

Ich weiß, dass andere dies erwähnt haben, und Sie möchten es nicht hören, sondern SQL * Loader oder externe Tabellen verwenden. Meine durchschnittliche Ladezeit für Tabellen mit ungefähr derselben Breite beträgt 12,57 Sekunden für knapp über 10m Reihen. Diese Dienstprogramme wurden explizit entwickelt, um Daten schnell in die Datenbank zu laden, und sind ziemlich gut darin. Dies kann je nach Format Ihrer Eingabedatei zu zusätzlichen Zeitstrafen führen, aber es gibt einige Optionen, und ich musste Dateien vor dem Laden selten ändern.

Wenn Sie dies nicht tun möchten, müssen Sie Ihre Hardware noch nicht aktualisieren. Sie müssen alle möglichen Hindernisse für das schnelle Laden beseitigen. Um sie aufzuzählen, entfernen Sie:

  1. Der Index
  2. Der Auslöser
  3. Die Reihenfolge
  4. Die Partition

Mit all dem zwingen Sie die Datenbank dazu, mehr Arbeit zu leisten, und da Sie dies transaktional tun, nutzen Sie das volle Potenzial der Datenbank nicht aus.

Laden Sie die Daten in eine separate Tabelle, sagen Sie ABC_LOAD . Nachdem die Daten vollständig geladen wurden, führen Sie einen single durch INSERT-Anweisung in ABC.

insert into abc
select abc_seq.nextval, a.*
  from abc_load a

Wenn Sie dies tun (und selbst wenn Sie dies nicht tun), stellen Sie sicher, dass die Größe des Sequenz-Cache korrekt ist; Zitat:

Wenn eine Anwendung auf eine Sequenz im Sequenz-Cache zugreift, werden diese Sequenznummern schnell gelesen. Wenn jedoch eine Anwendung auf eine Sequenz zugreift, die sich nicht im Cache befindet, muss die Sequenz von der Festplatte in den Cache gelesen werden, bevor die Sequenznummern verwendet werden.

Wenn Ihre Anwendungen viele Sequenzen gleichzeitig verwenden, ist Ihr Sequenzcache möglicherweise nicht groß genug, um alle Sequenzen aufzunehmen. In diesem Fall erfordert der Zugriff auf Sequenznummern häufig Lesevorgänge auf der Festplatte. Stellen Sie für einen schnellen Zugriff auf alle Sequenzen sicher, dass Ihr Cache über genügend Einträge verfügt, um alle Sequenzen aufzunehmen, die gleichzeitig von Ihren Anwendungen verwendet werden.

Das bedeutet, dass Sie, wenn Sie 10 Threads haben, die gleichzeitig 500 Datensätze mit dieser Sequenz schreiben, eine Cache-Größe von 5.000 benötigen. Das ALTER SEQUENCE-Dokument gibt an, wie dies geändert werden kann:

alter sequence abc_seq cache 5000

Wenn Sie meinem Vorschlag folgen, würde ich die Cache-Größe auf etwa 10,5 Millionen erhöhen.

Sehen Sie sich die Verwendung des APPEND-Hinweises an (siehe auch Oracle Base); Dadurch wird Oracle angewiesen, eine Direktpfadeinfügung zu verwenden, die Daten direkt an das Ende der Tabelle anhängt, anstatt nach Platz zu suchen, um sie einzufügen. Sie können dies nicht verwenden, wenn Ihre Tabelle Indizes hat, aber Sie könnten es in ABC_LOAD verwenden

insert /*+ append */ into ABC (SSM_ID, invocation_id , calc_id, ... )
select 'c','b',NULL, 'test', 123 , 'N', 'asdf' from dual
union all select 'a','b',NULL, 'test', 123 , 'N', 'asdf' from dual
union all select 'b','b',NULL, 'test', 123 , 'N', 'asdf' from dual
union all select 'c','g',NULL, 'test', 123 , 'N', 'asdf' from dual

Wenn Sie den APPEND-Hinweis verwenden; Ich würde TRUNCATE ABC_LOAD hinzufügen nachdem Sie in ABC eingefügt haben andernfalls wird diese Tabelle unendlich wachsen. Dies sollte sicher sein, da Sie bis dahin mit der Verwendung der Tabelle fertig sind.

Sie erwähnen nicht, welche Version oder Edition oder Oracle Sie verwenden. Es gibt eine Reihe zusätzlicher kleiner Tricks, die Sie anwenden können:

  • Oracle 12c

    Diese Version unterstützt Identitätsspalten; Sie könnten die Sequenz vollständig entfernen.

    CREATE TABLE ABC(
       seq_no         NUMBER GENERATED AS IDENTITY (increment by 5000)
    
  • Oracle 11g r2

    Wenn Sie den Auslöser halten; Sie können den Sequenzwert direkt zuweisen.

    :new.seq_no := ABC_seq.nextval;
    
  • Oracle Enterprise Edition

    Wenn Sie Oracle Enterprise verwenden, können Sie das INSERT von ABC_LOAD beschleunigen indem Sie den PARALLEL-Hinweis verwenden:

    insert /*+ parallel */ into abc
    select abc_seq.nextval, a.*
      from abc_load a
    

    Dies kann zu eigenen Problemen führen (zu viele parallele Prozesse usw.), also testen. Es vielleicht Hilfe für die kleineren Batch-Einfügungen, aber es ist weniger wahrscheinlich, da Sie Zeit verlieren werden, um zu berechnen, welcher Thread was verarbeiten soll.

tl;dr

Verwenden Sie die mit der Datenbank gelieferten Dienstprogramme.

Wenn Sie sie nicht verwenden können, entfernen Sie alles, was das Einfügen verlangsamen könnte, und führen Sie es in großen Mengen durch, denn darin ist die Datenbank gut.