sql >> Database teknologi >  >> RDS >> Oracle

Hvordan øger man ydeevnen for bulk INSERTs til ODBC-linkede tabeller i Access?

Denne situation er ikke ualmindeligt, når man håndterer bulk INSERTs til ODBC-linkede tabeller i Access. I tilfælde af følgende Access-forespørgsel

INSERT INTO METER_DATA (MPO_REFERENCE) 
SELECT MPO_REFERENCE FROM tblTempSmartSSP

hvor [METER_DATA] er en ODBC-linket tabel og [tblTempSmartSSP] er en lokal (native) Access-tabel, er ODBC noget begrænset i, hvor smart den kan være, fordi den skal være i stand til at rumme en bred vifte af måldatabaser, hvis muligheder kan variere i høj grad. Desværre betyder det ofte, at på trods af den enkelte Access SQL-sætning, er det, der faktisk sendes til den eksterne (linkede) database, en separat INSERT (eller tilsvarende) for hver række i den lokale tabel . Det kan forståeligt nok vise sig at være meget langsomt, hvis den lokale tabel indeholder et stort antal rækker.

Mulighed 1:Indbyggede masseindsættelser til fjerndatabasen

Alle databaser har en eller flere indbyggede mekanismer til masseindlæsning af data:Microsoft SQL Server har "bcp" og BULK INSERT , og Oracle har "SQL*Loader". Disse mekanismer er optimeret til bulkoperationer og vil normalt give betydelige hastighedsfordele. Faktisk, hvis dataene skal importeres til Access og "masseres", før de overføres til fjerndatabasen, kan det stadig være hurtigere at dumpe de ændrede data tilbage til en tekstfil og derefter masseimportere dem til fjerndatabasen.

Mulighed 2:Brug af en pass-through-forespørgsel i Access

Hvis masseimportmekanismerne ikke er en mulig mulighed, så er en anden mulighed at bygge en eller flere pass-through-forespørgsler i Access for at uploade dataene ved hjælp af INSERT-sætninger, der kan indsætte mere end én række ad gangen.

For eksempel, hvis fjerndatabasen var SQL Server (2008 eller nyere), så kunne vi køre en Access pass-through (T-SQL) forespørgsel som denne

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

for at indsætte tre rækker med én INSERT-sætning.

Ifølge et svar på et andet tidligere spørgsmål her ville den tilsvarende syntaks for Oracle væ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;

Jeg testede denne tilgang med SQL Server (da jeg ikke har adgang til en Oracle-database) ved hjælp af en indbygget [tblTempSmartSSP]-tabel med 10.000 rækker. Koden ...

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

... tog cirka 100 sekunder at udføre i mit testmiljø.

Derimod følgende kode, som bygger INSERT'er med flere rækker som beskrevet ovenfor (ved at bruge det, Microsoft kalder en Table Value Constructor) ...

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

... tog mellem 1 og 2 sekunder at producere de samme resultater.

(T-SQL Table Value Constructors er begrænset til at indsætte 1000 rækker ad gangen, så ovenstående kode er en smule mere kompliceret, end den ellers ville være.)



  1. Få top n poster for hver gruppe af grupperede resultater

  2. Arbejde med Salesforce.com-data i SQL Server Reporting Services

  3. konverter Postgres geometriformat til WKT

  4. Hvad betyder følgende Oracle-fejl:ugyldigt kolonneindeks