将Excel表格数据传输到SQL 2008R2的最快方法

有没有人知道最快的方式从SQL 2008中获取数据和Excel表(VBA数组)到一个表, 而不使用外部工具(即BCP)? 请记住我的数据集通常是6500-15000行,大约150-250列; 最终我在一个自动化的VBA批处理脚本中传输了大约20-150个。

我已经尝试了从Excel表格(VBA)中获取大量数据到SQL 2008的几种方法。我已经列出了以下内容:

方法1.将表传递到VBA数组并发送到存储过程(ADO) – 发送到SQL是SLOW

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

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

方法4.将表放到VBA数组中,循环数组并循环(使用分隔符),然后用ADOlogging集.addnew命令放置每一行。 – 发送到SQL非常快(比方法1-3快大约20倍),但是现在我需要使用单独的过程来拆分这些数据,这将增加显着的等待时间。

方法5.将表放在VBA数组中,序列化成XML,作为VARCHAR发送到存储过程,并在存储过程中指定XML。 – 发送到SQL INCREDIBLY SLOW(比方法1或2慢大约100倍)

我错过了什么?

没有一种最快的方法,因为它取决于许多因素。 确保SQL中的索引已configuration和优化。 大量的索引会杀死插入/更新性能,因为每个插入都需要更新索引。 确保只与数据库build立一个连接,在操作过程中不要打开/closures它。 在服务器处于最低负载时运行更新。 您唯一没有尝试的其他方法是使用ADO Command对象,并发出直接的INSERT语句。 当使用logging集对象的“AddNew”方法时,请确保在插入结束时只发出一个“UpdateBatch”命令。 除此之外,VBA只能运行接受input的SQL服务器。

编辑:似乎你已经尝试了一切。 在SQL Server中还有一种称为“批量logging”的恢复模式,可以减less写入事务日志的开销。 可能是值得研究的东西。 这可能会很麻烦,因为它需要稍微摆弄一下数据库恢复模型,但是它可能对您有用。

以下代码将在几秒钟(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 

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

有几个警告。

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

开始时我花了一些尝试和错误,但是与其他我尝试过的技术相比,性能的提高是惊人的。

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

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

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

这里是我们只需要列名。 因此,不需要为整个表做一个查询,只要导入新的数据就可以扩展整个表。

据我所知,你可以创build一个到Excel文件的链接服务器(只要服务器可以findpath;最好把文件放在服务器的本地磁盘上),然后用SQL从它检索数据。