sql >> Databasteknik >  >> RDS >> Oracle

Hur ökar man prestanda för bulk INSERTs till ODBC länkade tabeller i Access?

Denna situation är inte ovanlig när man hanterar bulk INSERTs till ODBC-länkade tabeller i Access. I fallet med följande Access-fråga

INSERT INTO METER_DATA (MPO_REFERENCE) 
SELECT MPO_REFERENCE FROM tblTempSmartSSP

där [METER_DATA] är en ODBC-länkad tabell och [tblTempSmartSSP] är en lokal (native) Access-tabell, är ODBC något begränsad i hur smart den kan vara eftersom den måste kunna ta emot ett brett utbud av måldatabaser vars kapacitet kan variera mycket. Tyvärr betyder det ofta att trots den enda Access SQL-satsen vad som faktiskt skickas till den fjärranslutna (länkade) databasen är en separat INSERT (eller motsvarande) för varje rad i den lokala tabellen . Förståeligt nog kan det visa sig vara väldigt långsamt om den lokala tabellen innehåller ett stort antal rader.

Alternativ 1:Inbyggda massinlägg till fjärrdatabasen

Alla databaser har en eller flera inbyggda mekanismer för bulkladdning av data:Microsoft SQL Server har "bcp" och BULK INSERT , och Oracle har "SQL*Loader". Dessa mekanismer är optimerade för bulkoperationer och kommer vanligtvis att erbjuda betydande hastighetsfördelar. Faktum är att om data behöver importeras till Access och "masseras" innan de överförs till fjärrdatabasen kan det fortfarande gå snabbare att dumpa den modifierade informationen tillbaka till en textfil och sedan massimportera den till fjärrdatabasen.

Alternativ 2:Använda en genomkopplingsfråga i Access

Om massimportmekanismerna inte är ett genomförbart alternativ, är en annan möjlighet att bygga en eller flera genomkopplingsfrågor i Access för att ladda upp data med hjälp av INSERT-satser som kan infoga mer än en rad åt gången.

Till exempel, om fjärrdatabasen var SQL Server (2008 eller senare) skulle vi kunna köra en Access pass-through-fråga (T-SQL) så här

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

för att infoga tre rader med en INSERT-sats.

Enligt ett svar på en annan tidigare fråga här skulle motsvarande syntax för Oracle vara

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;

Jag testade detta tillvägagångssätt med SQL Server (eftersom jag inte har tillgång till en Oracle-databas) med en inbyggd [tblTempSmartSSP]-tabell med 10 000 rader. 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 ungefär 100 sekunder att köra i min testmiljö.

Däremot följande kod, som bygger INSERT med flera rader enligt beskrivningen ovan (med vad Microsoft kallar 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 mellan 1 och 2 sekunder att producera samma resultat.

(T-SQL-tabellvärdekonstruktörer är begränsade till att infoga 1000 rader åt gången, så ovanstående kod är lite mer komplicerad än den skulle vara annars.)



  1. Hur avrundar man till närmaste X minuter med PL/pgSQL?

  2. Simulera ORDER BY i SQLite UPDATE för att hantera unikhetsbegränsningar

  3. Mjukvaruföretag som arbetar med Oracle D2k, PLSQL Technologies i Noida

  4. Hur fixar man fel i pg_dump-versionen?