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 万条“禁飞名单”被泄露
如果在单个请求中与 Oracle 和 PostgreSql 交互以处理超过 20 万条记录,如何提高 EF Core 性能