我一直在寻求提高 vb.net 程序中表更新的速度。
场景是我有一个包含 10,000 行和 160 列的表。
该表已更新非常频繁,每行有 1 到 100 多个列更改。
使用 DataAdapter
更新非常慢且不合适,并且已进行调查但没有改进结果。
下一个选项很可能是使用bulkcopy
将数据转储到临时表中的过程,删除原始数据库表中的所有行,然后发出复制命令以将数据从临时表中移动。将暂存表恢复到我想要更新的原始表。
考虑到数据运行的程序执行期间更新过程会发生 30-50 次,速度差异是惊人的
数据适配器更新 = 10-15 秒乘以 50 = 12.5 分钟
如上所述的批量更新 = 1.2-1.4 秒乘以 50 = 1.16 分钟
非凡的差异!所以我真的很想采用批量更新选项。
我知道这不是传统的,但这个表将保持在 10,000 行,并且该程序是单线程单用户本地数据库,消除了很多潜在的问题。
我主要关心的是数据安全。
我已经将代码封装在 try-catch 中,但也许有一种方法可以确保所有涉及 SQL 事务的进程都正确运行,就像在银行中一样,因此如果出现问题,一切都会逆转。
鉴于我的技能水平无法超越创建下面的代码。
该程序的最佳实现方式是什么?
Try
ESTP = "Start Bulk DBselection Update"
Dim oMainQueryT = "Truncate Table DBSelectionsSTAGE"
Using con As New SqlClient.SqlConnection(RacingConStr)
Using cmd As New SqlClient.SqlCommand(oMainQueryT, con)
con.Open()
cmd.ExecuteNonQuery()
con.Close()
End Using
End Using
ESTP = "Step 1 Bulk DBselection Update"
Using bulkCopy As SqlBulkCopy = New SqlBulkCopy(RacingConStr)
bulkCopy.DestinationTableName = "DBSelectionsSTAGE"
bulkCopy.WriteToServer(DBSelectionsDS.Tables("DBSelectionsDetails"))
bulkCopy.Close()
End Using
ESTP = "Step 2 Bulk DBselection Update"
oMainQueryT = "Truncate Table DBSelections"
Using con As New SqlClient.SqlConnection(RacingConStr)
Using cmd As New SqlClient.SqlCommand(oMainQueryT, con)
con.Open()
cmd.ExecuteNonQuery()
con.Close()
End Using
End Using
ESTP = "Step 3 Bulk DBselection Update"
oMainQueryT = "Insert INTO DBSelections Select * FROM DBSelectionsSTAGE"
Using con As New SqlClient.SqlConnection(RacingConStr)
Using cmd As New SqlClient.SqlCommand(oMainQueryT, con)
con.Open()
cmd.ExecuteNonQuery()
con.Close()
End Using
End Using
Data_Base.TextBox25.Text = "Deleting data - DONE "
Data_Base.TextBox25.Refresh()
DBSelectionsDS.Tables("DBSelectionsDetails").AcceptChanges()
Catch ex As Exception
ErrMess = "ERROR - occured at " & ESTP & " " & ex.ToString
Call WriteError()
Call ViewError()
End Try
编辑:我将代码合并到我的项目中并采用了 Dan 建议的更改。
现在“更新”只需不到一秒。这对之前的代码来说是一个巨大的改进。我不确定它的扩展效果如何,但在我的情况下,表保持大致相同的大小(行数),我对结果非常满意。
完成后不要忘记接受数据表上的更改DBSelectionsDS.Tables("DBSelectionsDetails").AcceptChanges()
最佳答案
考虑用事务性 TRUNCATE
和 SWITCH
替换步骤 2 和 3,以用暂存数据替换 DBSelection
表的内容。 SWITCH 比复制各个行更有效,因为它是仅元数据操作。
SWITCH
通常在 SQL Server Enterprise Edition 中用于将数据移入(而非复制)分区表或从分区表中移出数据,但它也可用于非分区表和较低版本。 SWITCH 的基本要求是源表和目标表具有相同的架构(包括索引)、驻留在相同的文件组中并且目标为空。操作后源暂存表将为空。请参阅https://technet.microsoft.com/en-us/library/ms191160.aspx有关SWITCH
的更多详细信息。
下面是如何实现此技术的示例。
Try
ESTP = "Start Bulk DBselection Update"
Dim oMainQueryT = "Truncate Table DBSelectionsSTAGE"
Using con As New SqlClient.SqlConnection(RacingConStr)
Using cmd As New SqlClient.SqlCommand(oMainQueryT, con)
con.Open()
cmd.ExecuteNonQuery()
con.Close()
End Using
End Using
ESTP = "Step 1 Bulk DBselection Update"
Using bulkCopy As SqlBulkCopy = New SqlBulkCopy(RacingConStr)
bulkCopy.DestinationTableName = "DBSelectionsSTAGE"
bulkCopy.WriteToServer(DBSelectionsDS.Tables("DBSelectionsDetails"))
bulkCopy.Close()
End Using
ESTP = "Step 2 and 3 - replace DBselection with staged data"
oMainQueryT = _
"SET XACT_ABORT ON;" + _
"BEGIN TRAN;" + _
"TRUNCATE TABLE dbo.DBSelections;" + _
"ALTER TABLE dbo.DBSelectionsSTAGE SWITCH TO dbo.DBSelections;" + _
"COMMIT;"
Using con As New SqlClient.SqlConnection(RacingConStr)
Using cmd As New SqlClient.SqlCommand(oMainQueryT, con)
con.Open()
cmd.ExecuteNonQuery()
con.Close()
End Using
End Using
Data_Base.TextBox25.Text = "Replaced data - DONE "
Data_Base.TextBox25.Refresh()
Catch ex As Exception
ErrMess = "ERROR - occured at " & ESTP & " " & ex.ToString
Call WriteError()
Call ViewError()
End Try
关于sql-server - SQL数据库表批量更新的陷阱,在vb.net中使用临时表和批量复制,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/30089055/