200万条记录的SqlDataAdapter.Update()速度极慢

Posted

技术标签:

【中文标题】200万条记录的SqlDataAdapter.Update()速度极慢【英文标题】:SqlDataAdapter.Update() of 2 million records is extremely slow 【发布时间】:2019-04-30 09:22:51 【问题描述】:

我有一个客户希望每天将他的子客户价格工具(超过 2.000.000 条记录)导入 SQL Server 数据库(是的....每天有超过 900.000 行更改)。

数据以 CSV 格式(不是 RFC-4180 标准 ç_ç,而是 nvm)提供,可以是数据的插入、删除或更新。

我的问题是在数据库中插入数据需要超过 1 个晚上才能结束,我需要加快速度。

我现在正在做的是:

将 csv 文件转换为数据表 (Tab1)(约 3 分钟) 选择上一个表 (Tab0) 中的所有数据并将它们与 Tab1 匹配(约 15 分钟,未更改的行被标记为未修改,因此它们在 adapter.Update 中被忽略,我检查了第一行的内容并且似乎可行,我使用dataRowToProcess.AcceptChanges() 来实现这一点)。

启动以下命令以应用更改(900.000 更改超过 5 小时):

cmdSQL = New SqlCommand(superQuery, cn)

Dim adapter As SqlDataAdapter = New SqlDataAdapter(cmdSQL)
adapter.MissingSchemaAction = MissingSchemaAction.AddWithKey

Dim build As SqlCommandBuilder = New SqlCommandBuilder(adapter)
build.SetAllValues = False

adapter.Update(dataTableCustomersDetail) 'Insert/Update records

如果我有很多插入过程,它会比相同数量的更新慢。 我究竟做错了什么?我错过了一些SqlDataAdapter 选项吗?

谢谢

【问题讨论】:

对于SqlBulkCopy,这应该是几秒钟或几分钟的问题,具体取决于您的硬件。 有趣的想法....但是没有为安全策略提供对源数据库的访问权限,所以我需要使用导出(来自第 3 方)/导入过程。或者我可以在数据表上打开阅读器? 不需要访问源数据库。您可以使用已从 csv 文件生成的 DataTable。由于SqlBulkCopy 只能插入但不能更新记录,您需要插入到临时临时表中,然后插入/更新记录。这里已经有一个类似的线程:***.com/questions/4889123/… 现在插入临时表并进行合并数据只需不到 10 分钟...永远不要认为它可以带来如此大的不同!非常感谢。 【参考方案1】:

感谢@matsnow,我想出了一个使用 SqlBulkCopy 的解决方案。考虑到表的一半每次都发生变化并且这是一个静态分析,我决定删除/插入数据是最快的方法(现在需要 5-6 分钟而不是 10 分钟)。

代码:

'Delete all table content
Dim cmd As SqlCommand = New SqlCommand("TRUNCATE TABLE " + tableName, cn)
cmd.ExecuteNonQuery()
'Insert all records
Using sbc As SqlBulkCopy = New SqlBulkCopy(cn)
    sbc.DestinationTableName = tableName
    sbc.BulkCopyTimeout = 1000
    For Each column As DataColumn In dataTableCustomersDetail.Columns
        sbc.ColumnMappings.Add(column.ToString(), column.ToString())
    Next
    sbc.WriteToServer(dataTableCustomersDetail)
End Using

【讨论】:

【参考方案2】:

使用 Connection.BeginTransaction() 加速 DataAdapter 更新。

cn.Open() 'open connection
Dim myTrans As SQLTransaction
myTrans = cn.BeginTransaction() 
'Associate the transaction with the select command object of the DataAdapter
adapter.SelectCommand.Transaction = myTrans 

adapter.Update(dataTableCustomersDetail) 'do the update as before

Try
    myTrans.Commit()
Catch ex As Exception
    myTrans.Rollback()
End Try
cn.Close()

对于 8000 行,这会将更新时间从 5 分钟以上更改为 2 秒

【讨论】:

以上是关于200万条记录的SqlDataAdapter.Update()速度极慢的主要内容,如果未能解决你的问题,请参考以下文章

对总计超过200万条记录(行)的多个输入文件(固定空格分隔的42列txt文件)进行合并排序和合并

Elasticsearch 又双叒发生数据泄露了,近 200 万条“禁飞名单”被泄露

Elasticsearch 又双叒发生数据泄露了,近 200 万条“禁飞名单”被泄露

超过 500 万条记录的 MongoDB 查询性能

200万数据oracle导入表要多久

如果在单个请求中与 Oracle 和 PostgreSql 交互以处理超过 20 万条记录,如何提高 EF Core 性能