oracle - 如何提高 Access 中 ODBC 链接表的批量插入性能?

标签 oracle ms-access odbc vba ms-access-2003

我有 CSV 和 TXT 文件要导入。我将文件导入到 Access 中,然后将记录插入到链接的 Oracle 表中。每个文件大约有 300 万行,并且该过程需要很长时间才能完成。

导入 Access 的速度非常快,但插入链接的 Oracle 表需要非常长的时间。

这是我当前正在使用的流程:

DoCmd.TransferText acImportFixed, "BUSSEP2014 Link Specification", "tblTempSmartSSP", strFName, False
db.Execute "INSERT INTO METER_DATA ([MPO_REFERENCE]) SELECT MPO_REFERENCE FROM tblTempSmartSSP;"`

tblTempSmartSSP 是一个 Access 表,METER_DATA 是一个链接的 Oracle 表

我也尝试过直接导入链接表,但速度也很慢。

如何加快该过程?

最佳答案

在 Access 中处理对 ODBC 链接表的批量插入时,这种情况并不少见。在以下 Access 查询的情况下

INSERT INTO METER_DATA (MPO_REFERENCE) 
SELECT MPO_REFERENCE FROM tblTempSmartSSP

其中 [METER_DATA] 是 ODBC 链接表,[tblTempSmartSSP] 是本地( native )Access 表,Access 数据库引擎在使用 ODBC 链接表时受到一定限制,因为它必须能够容纳范围广泛的目标数据库,其功能可能差异很大。不幸的是,这通常意味着尽管有单个 Access SQL 语句,但实际发送到远程(链接)数据库的是本地表中每一行的单独 INSERT(或等效语句)。可以理解的是,如果本地表包含大量行,这可能会非常慢。

选项 1: native 批量插入到远程数据库

所有数据库都有一种或多种用于批量加载数据的 native 机制:Microsoft SQL Server 具有“bcp”和BULK INSERT,Oracle 具有“SQL*Loader”。这些机制针对批量操作进行了优化,通常会提供显着的速度优势。事实上,如果数据需要导入到 Access 中并在传输到远程数据库之前进行“修改”,那么将修改后的数据转储回文本文件,然后将其批量导入到远程数据库中仍然会更快。

选项 2(a):使用 Python 和 pandas

使用 fast_executemany=True 的 pyodbc 上传行的速度比链接表上的 INSERT INTO … SELECT … 快得多。请参阅this answer了解详情。

选项 2(b):在 Access 中使用传递查询

如果批量导入机制不是一个可行的选择,那么另一种可能性是在 Access 中构建一个或多个传递查询,以使用可一次插入多行的 INSERT 语句上传数据。

例如,如果远程数据库是 SQL Server(2008 或更高版本),那么我们可以像这样运行 Access 传递 (T-SQL) 查询

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

使用一个 INSERT 语句插入三行。

根据之前另一个问题的回答here Oracle 的相应语法是

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;

我使用包含 10,000 行的 native [tblTempSmartSSP] 表通过 SQL Server(因为我无法 Access Oracle 数据库)测试了这种方法。代码...

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

...在我的测试环境中执行大约需要 100 秒。

相比之下,下面的代码如上所述构建多行插入(使用 Microsoft 所谓的 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

...需要 1 到 2 秒才能产生相同的结果。

(T-SQL 表值构造函数仅限于一次插入 1000 行,因此上面的代码比其他情况要复杂一些。)

关于oracle - 如何提高 Access 中 ODBC 链接表的批量插入性能?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/25863473/

相关文章:

html - 链接到数据库(独立)以使用 html/css 页面进行测试

delphi - 使用 Delphi 以编程方式获取 ODBC 数据源名称列表

ssl - MSDASQL.1 是否支持 TLS1.2

java - 如何在oracle存储过程中返回自己类型的数据?

java - Spring boot 应用程序错误日志显示尝试在 FanManager 中配置 ONS 失败,并出现 oracle.ons.NoServersAvailable

oracle - 将单行结果集转换为关联数组

java - dsn less 连接不适用于 java

excel - 更新 MS - 通过 MS-Excel 单元格 Access 字段

mysql - 在asp.net中连接mysql数据库时出现连接错误

Java、时间相关对象和oracle to_date函数