Tình huống này không phải là hiếm khi xử lý INSERT hàng loạt cho các bảng được liên kết ODBC trong Access. Trong trường hợp truy vấn Access sau
INSERT INTO METER_DATA (MPO_REFERENCE)
SELECT MPO_REFERENCE FROM tblTempSmartSSP
trong đó [METER_DATA] là bảng được liên kết ODBC và [tblTempSmartSSP] là bảng Access cục bộ (gốc), ODBC hơi hạn chế về mức độ thông minh của nó vì nó phải có khả năng cung cấp nhiều loại cơ sở dữ liệu mục tiêu có khả năng khác nhau rất nhiều. Thật không may, điều đó thường có nghĩa là mặc dù một câu lệnh Access SQL duy nhất, những gì thực sự được gửi đến cơ sở dữ liệu từ xa (được liên kết) là một INSERT riêng biệt (hoặc tương đương) cho mỗi hàng trong bảng cục bộ . Nói một cách dễ hiểu, điều đó có thể diễn ra rất chậm nếu bảng cục bộ chứa một số lượng lớn các hàng.
Tùy chọn 1:Chèn hàng loạt gốc vào cơ sở dữ liệu từ xa
Tất cả các cơ sở dữ liệu đều có một hoặc nhiều cơ chế riêng để tải dữ liệu hàng loạt:Microsoft SQL Server có "bcp" và BULK INSERT
và Oracle có "SQL * Loader". Các cơ chế này được tối ưu hóa cho các hoạt động hàng loạt và thường sẽ mang lại lợi thế về tốc độ đáng kể. Trên thực tế, nếu dữ liệu cần được nhập vào Access và được "xoa bóp" trước khi được chuyển đến cơ sở dữ liệu từ xa, thì việc kết xuất dữ liệu đã sửa đổi trở lại tệp văn bản và sau đó nhập hàng loạt vào cơ sở dữ liệu từ xa vẫn có thể nhanh hơn.
Tùy chọn 2:Sử dụng truy vấn chuyển tiếp trong Access
Nếu cơ chế nhập hàng loạt không phải là một tùy chọn khả thi, thì một khả năng khác là tạo một hoặc nhiều truy vấn chuyển qua trong Access để tải lên dữ liệu bằng cách sử dụng câu lệnh INSERT có thể chèn nhiều hàng cùng một lúc.
Ví dụ:nếu cơ sở dữ liệu từ xa là SQL Server (2008 trở lên) thì chúng tôi có thể chạy truy vấn chuyển qua Access (T-SQL) như thế này
INSERT INTO METER_DATA (MPO_REFERENCE) VALUES (1), (2), (3)
để chèn ba hàng với một câu lệnh INSERT.
Theo một câu trả lời cho một câu hỏi khác trước đó ở đây, cú pháp tương ứng cho Oracle sẽ là
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;
Tôi đã thử nghiệm phương pháp này với SQL Server (vì tôi không có quyền truy cập vào cơ sở dữ liệu Oracle) bằng cách sử dụng bảng [tblTempSmartSSP] gốc có 10.000 hàng. Mã ...
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
... mất khoảng 100 giây để thực thi trong môi trường thử nghiệm của tôi.
Ngược lại, đoạn mã sau tạo các INSERT nhiều hàng như được mô tả ở trên (sử dụng cái mà Microsoft gọi là Bộ tạo giá trị bảng) ...
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
... mất từ 1 đến 2 giây để tạo ra kết quả tương tự.
(Trình tạo giá trị bảng T-SQL được giới hạn trong việc chèn 1000 hàng cùng một lúc, vì vậy đoạn mã trên phức tạp hơn một chút so với cách khác.)