9

有谁知道在使用外部实用程序(即 bcp)的情况下从 Excel 表(VBA 数组)获取数据到 SQL 2008 表的最快方法?请记住,我的数据集通常是 6500-15000 行,大约 150-250 列;我最终在自动 VBA 批处理脚本中传输了大约 20-150 个。

我已经尝试了几种方法从 Excel 表 (VBA) 获取大量数据到 SQL 2008。我在下面列出了这些:

方法 1. 将表传递到 VBA 数组并发送到存储过程 (ADO) -- 发送到 SQL 很慢

方法2. 创建断开连接的RecordSet 加载它,然后同步。-- 发送到 SQL 非常慢

方法 3. 将表放入 VBA 数组,遍历数组并连接(使用分隔符)然后发送到存储过程。-- 发送到 SQL SLOW,但比方法 1 或 2 快。

方法 4. 将表放入 VBA 数组,循环遍历数组并连接(使用分隔符),然后使用 ADO 记录集 .addnew 命令放置每一行。-- 发送到 SQL 非常快(比方法 1-3 快大约 20 倍),但现在我需要使用单独的过程拆分该数据,这将增加大量等待时间。

方法 5. 将表放入 VBA 数组,序列化为 XML,以 VARCHAR 形式发送到存储过程,并在存储过程中指定 XML。-- 发送到 SQL 非常慢(比方法 1 或 2 慢大约 100 倍)

有什么我想念的吗?

4

6 回答 6

2

没有单一的最快方法,因为它取决于许多因素。确保 SQL 中的索引已配置和优化。许多索引会破坏插入/更新性能,因为每个插入都需要更新索引。确保只与数据库建立一个连接,并且在操作过程中不要打开/关闭它。在服务器负载最小时运行更新。您还没有尝试过的唯一其他方法是使用 ADO Command 对象,并发出直接的 INSERT 语句。使用记录集对象的“AddNew”方法时,请确保在插入结束时只发出一个“UpdateBatch”命令。除此之外,VBA 的运行速度只能与接受输入的 SQL 服务器一样快。

编辑:好像你已经尝试了一切。SQL Server 中还有所谓的“批量记录”恢复模式,它减少了写入事务日志的开销。可能是值得研究的东西。这可能很麻烦,因为它需要稍微修改数据库恢复模型,但它可能对您有用。

于 2012-05-22T19:50:08.747 回答
2

以下代码将在几秒钟(2-3 秒)内传输数千条数据。

Dim sheet As Worksheet
    Set sheet = ThisWorkbook.Sheets("DataSheet")        

    Dim Con As Object
    Dim cmd As Object
    Dim ServerName As String
    Dim level As Long
    Dim arr As Variant
    Dim row As Long
    Dim rowCount As Long

    Set Con = CreateObject("ADODB.Connection")
    Set cmd = CreateObject("ADODB.Command")

    ServerName = "192.164.1.11" 

    'Creating a connection
    Con.ConnectionString = "Provider=SQLOLEDB;" & _
                                    "Data Source=" & ServerName & ";" & _
                                    "Initial Catalog=Adventure;" & _
                                    "UID=sa; PWD=123;"

    'Setting provider Name
     Con.Provider = "Microsoft.JET.OLEDB.12.0"

    'Opening connection
     Con.Open                

    cmd.CommandType = 1             ' adCmdText

    Dim Rst As Object
    Set Rst = CreateObject("ADODB.Recordset")
    Table = "EmployeeDetails" 'This should be same as the database table name.
    With Rst
        Set .ActiveConnection = Con
        .Source = "SELECT * FROM " & Table
        .CursorLocation = 3         ' adUseClient
        .LockType = 4               ' adLockBatchOptimistic
        .CursorType = 0             ' adOpenForwardOnly
        .Open

        Dim tableFields(200) As Integer
        Dim rangeFields(200) As Integer

        Dim exportFieldsCount As Integer
        exportFieldsCount = 0

        Dim col As Integer
        Dim index As Integer
        index = 1

        For col = 1 To .Fields.Count
            exportFieldsCount = exportFieldsCount + 1
            tableFields(exportFieldsCount) = col
            rangeFields(exportFieldsCount) = index
            index = index + 1
        Next

        If exportFieldsCount = 0 Then
            ExportRangeToSQL = 1
            GoTo ConnectionEnd
        End If            

        endRow = ThisWorkbook.Sheets("DataSheet").Range("A65536").End(xlUp).row 'LastRow with the data.
        arr = ThisWorkbook.Sheets("DataSheet").Range("A1:CE" & endRow).Value 'This range selection column count should be same as database table column count.

        rowCount = UBound(arr, 1)            

        Dim val As Variant

        For row = 1 To rowCount
            .AddNew
            For col = 1 To exportFieldsCount
                val = arr(row, rangeFields(col))
                    .Fields(tableFields(col - 1)) = val
            Next
        Next

        .UpdateBatch
    End With

    flag = True

    'Closing RecordSet.
     If Rst.State = 1 Then
       Rst.Close
    End If

   'Closing Connection Object.
    If Con.State = 1 Then
      Con.Close
    End If

'Setting empty for the RecordSet & Connection Objects
Set Rst = Nothing
Set Con = Nothing
End Sub
于 2013-12-12T10:04:52.287 回答
0

到目前为止,最快的方法是通过 T-SQL 的BULK INSERT.

有一些注意事项。

  • 您可能需要先将数据导出到 csv (您可以直接从 Excel 导入;我的经验是从 Access .mdbs 转到 SQL Server,这需要到 csv 的中间步骤)。
  • SQL Server 机器需要有权访问该 csv(当您运行BULK INSERT命令并指定文件名时,请记住文件名将在运行 SQL Server 的机器上解析)。
  • 您可能需要调整默认值FIELDTERMINATORROWTERMINATOR值以匹配您的 CSV。

我最初进行了一些尝试和错误的设置,但与我尝试过的所有其他技术相比,性能提升是惊人的。

于 2012-05-22T20:53:16.947 回答
0

工作得很好,另一方面为了提高速度,我们仍然可以修改查询:

反而:Source = "SELECT * FROM " & Table

我们可以用:Source = "SELECT TOP 1 * FROM " & Table

这里我们只需要列名。因此无需对整个表进行查询,只要导入新数据就可以扩展流程。

于 2015-08-12T06:37:58.243 回答
0

据我记得,你可以创建一个链接到Excel文件的服务器(只要服务器能找到路径;最好把文件放在服务器的本地磁盘上),然后使用SQL从中检索数据。

于 2017-03-15T16:57:23.513 回答
0

刚刚尝试了几种方法,我又回到了一种相对简单但速度很快的方法。它的速度很快,因为它使 SQL 服务器完成所有工作,包括高效的执行计划。

我只是构建了一个包含 INSERT 语句脚本的长字符串。

    Public Sub Upload()
        Const Tbl As String = "YourTbl"
        Dim InsertQuery As String, xlRow As Long, xlCol As Integer
        Dim DBconnection As New ADODB.Connection

        DBconnection.Open "Provider=SQLOLEDB.1;Password=MyPassword" & _
            ";Persist Security Info=false;User ID=MyUserID" & _
            ";Initial Catalog=MyDB;Data Source=MyServer"

        InsertQuery = ""
        xlRow = 2
        While Cells(xlRow, 1) <> ""
            InsertQuery = InsertQuery & "INSERT INTO " & Tbl & " VALUES('"

            For xlCol = 1 To 6 'Must match the table structure
                InsertQuery = InsertQuery & Replace(Cells(xlRow, xlCol), "'", "''") & "', '"  'Includes mitigation for apostrophes in the data
            Next xlCol
            InsertQuery = InsertQuery & Format(Now(), "M/D/YYYY") & "')" & vbCrLf 'The last column is a date stamp, either way, don't forget to close that parenthesis
            xlRow = xlRow + 1
        Wend

        DBconnection.Execute InsertQuery 'I'll leave any error trapping to you
        DBconnection.Close  'But do be tidy :-)
        Set DBconnection = Nothing
    End Sub
于 2017-12-20T23:04:00.870 回答