Questa situazione non è rara quando si tratta di INSERT in blocco alle tabelle collegate ODBC in Access. Nel caso della seguente query di accesso
INSERT INTO METER_DATA (MPO_REFERENCE)
SELECT MPO_REFERENCE FROM tblTempSmartSSP
dove [METER_DATA] è una tabella collegata ODBC e [tblTempSmartSSP] è una tabella di Access locale (nativa), ODBC è alquanto limitato in quanto può essere intelligente perché deve essere in grado di ospitare un'ampia gamma di database di destinazione le cui capacità possono variare notevolmente. Sfortunatamente, spesso significa che, nonostante la singola istruzione Access SQL, ciò che viene effettivamente inviato al database remoto (collegato) è un INSERT separato (o equivalente) per ogni riga nella tabella locale . Comprensibilmente, ciò può rivelarsi molto lento se la tabella locale contiene un numero elevato di righe.
Opzione 1:inserimenti collettivi nativi nel database remoto
Tutti i database hanno uno o più meccanismi nativi per il caricamento in blocco dei dati:Microsoft SQL Server ha "bcp" e BULK INSERT
e Oracle ha "SQL*Loader". Questi meccanismi sono ottimizzati per operazioni in blocco e di solito offrono vantaggi significativi in termini di velocità. Infatti, se i dati devono essere importati in Access e "massaggiati" prima di essere trasferiti al database remoto, può essere ancora più veloce scaricare nuovamente i dati modificati in un file di testo e quindi importarli in blocco nel database remoto.
Opzione 2:utilizzo di una query pass-through in Access
Se i meccanismi di importazione in blocco non sono un'opzione fattibile, un'altra possibilità consiste nel creare una o più query pass-through in Access per caricare i dati utilizzando istruzioni INSERT che possono inserire più di una riga alla volta.
Ad esempio, se il database remoto era SQL Server (2008 o successivo), potremmo eseguire una query pass-through di accesso (T-SQL) come questa
INSERT INTO METER_DATA (MPO_REFERENCE) VALUES (1), (2), (3)
per inserire tre righe con un'istruzione INSERT.
Secondo una risposta a un'altra domanda precedente qui la sintassi corrispondente per Oracle sarebbe
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;
Ho testato questo approccio con SQL Server (poiché non ho accesso a un database Oracle) utilizzando una tabella nativa [tblTempSmartSSP] con 10.000 righe. Il codice...
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
... ci sono voluti circa 100 secondi per l'esecuzione nel mio ambiente di test.
Al contrario, il codice seguente, che crea INSERT a più righe come descritto sopra (usando ciò che Microsoft chiama un costruttore di valori di tabella) ...
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
... ci sono voluti tra 1 e 2 secondi per produrre gli stessi risultati.
(I costruttori di valori di tabella T-SQL sono limitati all'inserimento di 1000 righe alla volta, quindi il codice sopra è un po' più complicato di quanto sarebbe altrimenti.)