2014-09-16 9 views
7

Ich habe CSV- und TXT-Dateien zu importieren. Ich importiere die Dateien in Access und füge die Datensätze dann in eine verknüpfte Oracle-Tabelle ein. Jede Datei hat ungefähr 3 Millionen Zeilen und der Prozess dauert sehr lange.Wie Leistung für Bulk-INSERTs zu ODBC-verknüpften Tabellen in Access erhöhen?

Der Import in Access ist sehr schnell, aber das Einfügen in die verknüpfte Oracle-Tabelle dauert extrem lange. Hier

ist der Prozess, ich bin derzeit mit:

DoCmd.TransferText acImportFixed, "BUSSEP2014 Link Specification", "tblTempSmartSSP", strFName, False 
db.Execute "INSERT INTO METER_DATA ([MPO_REFERENCE]) SELECT MPO_REFERENCE FROM tblTempSmartSSP;"` 

tblTempSmartSSP ist eine Access-Tabelle und METER_DATA ist eine verknüpfte Oracle-Tabelle

ich auch den direkten Import zu verknüpften Tabelle versucht, und das war auch sehr langsam .

Wie kann ich den Prozess beschleunigen?

+0

Meter_Data ist eine Oracle-Datenbank-Tabelle –

Antwort

7

Diese Situation ist nicht ungewöhnlich, wenn sie mit Masseneinfügungen zu ODBC verknüpften Tabellen in Access handelt. Im Falle der folgenden Access-Abfrage

INSERT INTO METER_DATA (MPO_REFERENCE) 
SELECT MPO_REFERENCE FROM tblTempSmartSSP 

wo [METER_DATA] eine ODBC-verknüpfte Tabelle ist und [tblTempSmartSSP] ist eine lokale (nativ) Access-Tabelle, wird ODBC etwas begrenzt, wie klug es sein kann, weil es in der Lage sein, eine breite Palette von Zieldatenbanken unterzubringen, deren Fähigkeiten stark variieren können. Leider bedeutet dies oft, dass trotz der einzelnen Access SQL-Anweisung, die tatsächlich an die entfernte (verknüpfte) Datenbank gesendet wird, eine separate INSERT (oder gleichwertige) für jede Zeile in der lokalen Tabelle ist. Verständlicherweise kann sich dies als sehr langsam erweisen, wenn die lokale Tabelle eine große Anzahl von Zeilen enthält.

Option 1: Gebürtige bulk Einsätze in die entfernten Datenbank

Alle Datenbanken einen oder mehr nativen Mechanismen für den Bulk-Laden von Daten haben: Microsoft SQL Server hat „bcp“ und BULK INSERT und Oracle hat „SQL * Lader ". Diese Mechanismen sind für den Massenbetrieb optimiert und bieten normalerweise erhebliche Geschwindigkeitsvorteile. In der Tat, wenn die Daten in Access importiert und "massiert" werden müssen, bevor sie in die entfernte Datenbank übertragen werden, kann es noch schneller sein, die modifizierten Daten wieder in eine Textdatei zu exportieren und dann in die entfernte Datenbank zu importieren.

Option 2: eine Pass-Through-Abfrage in Access Mit

Wenn die Bulk-Import-Mechanismen keine gangbare Option sind, dann ist eine weitere Möglichkeit, eine oder mehrere bauen Abfragen in Access-Pass-Through die zum Hochladen Daten mit INSERT-Anweisungen, die mehr als eine Zeile gleichzeitig einfügen können.

Zum Beispiel, wenn die entfernte Datenbank SQL Server ist (2008 oder später), dann könnten wir eine Access-Pass-Through (T-SQL) Abfrage wie diese

INSERT INTO METER_DATA (MPO_REFERENCE) VALUES (1), (2), (3) 

einzufügen drei Reihen mit einer INSERT laufen Erklärung.

Nach einer Antwort auf eine andere Frage von vorhin here die entsprechende Syntax für Oracle wäre

INSERT ALL 
    INTO METER_DATA (MPO_REFERENCE) VALUES (1) 
    INTO METER_DATA (MPO_REFERENCE) VALUES (2) 
    INTO METER_DATA (MPO_REFERENCE) VALUES (3) 
SELECT * FROM DUAL; 

ich diesen Ansatz mit SQL Server getestet (wie ich haben keinen Zugang zu einer Oracle-Datenbank) unter Verwendung eines nativen [tblTempSmartSSP] Tabelle mit 10.000 Zeilen. Der Code ...

Sub LinkedTableTest() 
    Dim cdb As DAO.Database 
    Dim t0 As Single 

    t0 = Timer 
    Set cdb = CurrentDb 
    cdb.Execute _ 
      "INSERT INTO METER_DATA (MPO_REFERENCE) " & _ 
      "SELECT MPO_REFERENCE FROM tblTempSmartSSP", _ 
      dbFailOnError 
    Set cdb = Nothing 
    Debug.Print "Elapsed time " & Format(Timer - t0, "0.0") & " seconds." 
End Sub 

... dauerte ungefähr 100 Sekunden, um in meiner Testumgebung ausgeführt zu werden.

dagegen der folgende Code, die wie oben beschrieben mehrreihigen INSERTs aufbaut (was unter Verwendung von Microsoft aufruft Table Value Constructor a) ...

Sub PtqTest() 
    Dim cdb As DAO.Database, rst As DAO.Recordset 
    Dim t0 As Single, i As Long, valueList As String, separator As String 

    t0 = Timer 
    Set cdb = CurrentDb 
    Set rst = cdb.OpenRecordset("SELECT MPO_REFERENCE FROM tblTempSmartSSP", dbOpenSnapshot) 
    i = 0 
    valueList = "" 
    separator = "" 
    Do Until rst.EOF 
     i = i + 1 
     valueList = valueList & separator & "(" & rst!MPO_REFERENCE & ")" 
     If i = 1 Then 
      separator = "," 
     End If 
     If i = 1000 Then 
      SendInsert valueList 
      i = 0 
      valueList = "" 
      separator = "" 
     End If 
     rst.MoveNext 
    Loop 
    If i > 0 Then 
     SendInsert valueList 
    End If 
    rst.Close 
    Set rst = Nothing 
    Set cdb = Nothing 
    Debug.Print "Elapsed time " & Format(Timer - t0, "0.0") & " seconds." 
End Sub 

Sub SendInsert(valueList As String) 
    Dim cdb As DAO.Database, qdf As DAO.QueryDef 

    Set cdb = CurrentDb 
    Set qdf = cdb.CreateQueryDef("") 
    qdf.Connect = cdb.TableDefs("METER_DATA").Connect 
    qdf.ReturnsRecords = False 
    qdf.sql = "INSERT INTO METER_DATA (MPO_REFERENCE) VALUES " & valueList 
    qdf.Execute dbFailOnError 
    Set qdf = Nothing 
    Set cdb = Nothing 
End Sub 

... nahmen zwischen 1 und 2 Sekunden, um das gleiche zu erzeugen, Ergebnisse.

(T-SQL-Tabellenwert Konstrukteurs sind Einfügen 1000 Zeilen zu einer Zeit begrenzt, so dass der obige Code ein bisschen komplizierter, als es sonst wäre ist.)

+0

Very beeindruckende Gord. Als allgemeine Anmerkung wird oft angenommen, dass die Verwendung von sql insert-Anweisungen schneller ist als von dao.recordsets - sie sind nicht möglich, wenn die eine SQL-Anweisung einen recorsetloop ersetzen kann. Das Ausführen einer "ganzen" SQL-Zeichenfolge für jede Zeile ist jedoch viel langsamer als ein Recorset. Ich würde also vorschlagen, das Poster einfach ein einfaches Recordset auf dem verknüpften Tisch auszuprobieren. –

+0

Hallo Gord Thompson, danke für den Code. Ich erhalte einen Fehler beim Ausführen dieses Codes "ODBC-Call Failed" bei qdf.Execute dbFailOnError –

+0

@ravichaudhary Bitte stellen Sie eine [neue Frage] (http://StackOverflow.com/questions/ask) zeigen Ihren tatsächlichen Code. –

0

Müssen Sie alle Spalten importieren? Vielleicht möchten Sie, wenn überhaupt, leere Spalten auslassen; und auch Spalten, die für geschäftliche Zwecke nicht unbedingt notwendig sind

+0

ich alle brauchen die Spalten und maximal gibt es 5 Spalten. Ich versuche auch, kleine Daten wie 6000 Reihen zu importieren, es dauert auch mehr als eine Stunde –

+0

Nur daran gedacht; Verwenden Sie Folgendes, um Ihre Aktionsabfrage auszuführen. Vielleicht ist es langsam, weil Sie mehr Deklarationen benötigen: – user2290801

+0

Importieren Sie die Datei in eine vorhandene Tabelle? und, bist du der einzige Benutzer? Das Erstellen einer Tabelle benötigt mehr Zeit und Sie möchten keine anderen Benutzer in der Datenbank, wenn Sie importieren. Führen Sie außerdem eine Abfrage zum Löschen von Nullen aus, bevor Sie etwas anderes in der Spalte ausführen, über die Sie kopieren. Nulls verlangsamt die Dinge. Nur ein paar Ideen – user2290801

0

Sorry, habe ich vergessen, den Code enthalten:

Option Compare Database 
Option Explicit 

Public Function Run_Safe_SQL(strSQL) 
On Error GoTo Error_Handler 
Dim db As DAO.Database 

    Set db = CurrentDb() 
    db.Execute strSQL, dbFailOnError 
    DBEngine.Idle dbRefreshCache 
' DoEvents 

Exit_Here: 
    'Cleanup 
    Set db = Nothing 
    strSQL = "" 
    Exit Function 

Error_Handler: 
    MsgBox Err.Description & " " & Err.Number 

End Function 
Verwandte Themen