sql >> Databáze >  >> RDS >> Oracle

Jak zvýšit výkon pro hromadné INSERTy do propojených tabulek ODBC v Accessu?

Tato situace není neobvyklá při práci s hromadnými INSERTy do propojených tabulek ODBC v aplikaci Access. V případě následujícího Access dotazu

INSERT INTO METER_DATA (MPO_REFERENCE) 
SELECT MPO_REFERENCE FROM tblTempSmartSSP

kde [METER_DATA] je tabulka propojená s ODBC a [tblTempSmartSSP] je místní (nativní) přístupová tabulka, je ODBC poněkud omezené v tom, jak chytré může být, protože musí být schopné pojmout širokou škálu cílových databází, jejichž možnosti se mohou lišit. velmi. Bohužel to často znamená, že navzdory jedinému příkazu Access SQL to, co se ve skutečnosti odešle do vzdálené (propojené) databáze, je samostatný INSERT (nebo ekvivalent) pro každý řádek v místní tabulce . Pochopitelně se to může ukázat jako velmi pomalé, pokud místní tabulka obsahuje velký počet řádků.

Možnost 1:Nativní hromadné vkládání do vzdálené databáze

Všechny databáze mají jeden nebo více nativních mechanismů pro hromadné načítání dat:Microsoft SQL Server má "bcp" a BULK INSERT a Oracle má "SQL*Loader". Tyto mechanismy jsou optimalizovány pro hromadné operace a obvykle nabízejí značné výhody rychlosti. Ve skutečnosti, pokud je třeba data naimportovat do Accessu a „namasírovat“ před přenesením do vzdálené databáze, může být stále rychlejší vypsat upravená data zpět do textového souboru a poté je hromadně importovat do vzdálené databáze.

Možnost 2:Použití předávacího dotazu v aplikaci Access

Pokud mechanismy hromadného importu nejsou proveditelnou možností, pak další možností je vytvořit jeden nebo více předávacích dotazů v Accessu pro nahrání dat pomocí příkazů INSERT, které mohou vložit více než jeden řádek najednou.

Pokud byl například vzdálenou databází SQL Server (2008 nebo novější), mohli bychom spustit předávací dotaz Access (T-SQL) takto

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

pro vložení tří řádků jedním příkazem INSERT.

Podle odpovědi na jinou dřívější otázku zde odpovídající syntaxe pro Oracle by byla

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;

Tento přístup jsem testoval s SQL Serverem (protože nemám přístup k databázi Oracle) pomocí nativní tabulky [tblTempSmartSSP] s 10 000 řádky. Kód ...

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

... spuštění v mém testovacím prostředí trvalo přibližně 100 sekund.

Naproti tomu následující kód, který vytváří víceřádkové INSERTy, jak je popsáno výše (pomocí toho, co Microsoft nazývá konstruktor hodnoty tabulky) ...

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

... trvalo 1 až 2 sekundy k dosažení stejných výsledků.

(Konstruktory hodnot tabulky T-SQL jsou omezeny na vkládání 1000 řádků najednou, takže výše uvedený kód je o něco složitější, než by byl jinak.)



  1. Korupce MS Access Část 1:Běžné příčiny

  2. Nastavení hodnoty pro LIMIT při používání hromadného sběru

  3. PostgreSQL na vzestupu:2018 Postgres Findings &2019 Trends

  4. PostgreSQL vs. MySQL