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.)