Essa situação não é incomum ao lidar com INSERTs em massa para tabelas vinculadas ODBC no Access. No caso da seguinte consulta do Access
INSERT INTO METER_DATA (MPO_REFERENCE)
SELECT MPO_REFERENCE FROM tblTempSmartSSP
onde [METER_DATA] é uma tabela vinculada ao ODBC e [tblTempSmartSSP] é uma tabela de acesso local (nativa), o ODBC é um pouco limitado em quão inteligente pode ser porque deve ser capaz de acomodar uma ampla variedade de bancos de dados de destino cujas capacidades podem variar muito. Infelizmente, muitas vezes isso significa que, apesar da única instrução SQL Access, o que realmente é enviado para o banco de dados remoto (vinculado) é um INSERT separado (ou equivalente) para cada linha na tabela local . Compreensivelmente, isso pode ser muito lento se a tabela local contiver um grande número de linhas.
Opção 1:inserções em massa nativas no banco de dados remoto
Todos os bancos de dados têm um ou mais mecanismos nativos para o carregamento em massa de dados:Microsoft SQL Server tem "bcp" e
BULK INSERT
, e o Oracle tem "SQL*Loader". Esses mecanismos são otimizados para operações em massa e geralmente oferecem vantagens significativas de velocidade. Na verdade, se os dados precisarem ser importados para o Access e "massageados" antes de serem transferidos para o banco de dados remoto, ainda pode ser mais rápido despejar os dados modificados de volta para um arquivo de texto e importá-los em massa para o banco de dados remoto. Opção 2:usar uma consulta de passagem no Access
Se os mecanismos de importação em massa não forem uma opção viável, outra possibilidade é criar uma ou mais consultas de passagem no Access para carregar os dados usando instruções INSERT que podem inserir mais de uma linha por vez.
Por exemplo, se o banco de dados remoto fosse SQL Server (2008 ou posterior), poderíamos executar uma consulta de passagem de acesso (T-SQL) como esta
INSERT INTO METER_DATA (MPO_REFERENCE) VALUES (1), (2), (3)
para inserir três linhas com uma instrução INSERT.
De acordo com uma resposta a outra pergunta anterior aqui, a sintaxe correspondente para Oracle seria
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;
Testei essa abordagem com o SQL Server (pois não tenho acesso a um banco de dados Oracle) usando uma tabela nativa [tblTempSmartSSP] com 10.000 linhas. O código ...
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
... levou aproximadamente 100 segundos para ser executado no meu ambiente de teste.
Por outro lado, o código a seguir, que cria INSERTs de várias linhas conforme descrito acima (usando o que a Microsoft chama de construtor de valor de tabela) ...
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
... levou entre 1 e 2 segundos para produzir os mesmos resultados.
(Os construtores de valor de tabela T-SQL estão limitados a inserir 1.000 linhas por vez, portanto, o código acima é um pouco mais complicado do que seria de outra forma.)