sql-server - SQL数据库表批量更新的陷阱,在vb.net中使用临时表和批量复制

标签 sql-server database vb.net

我一直在寻求提高 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()

最佳答案

考虑用事务性 TRUNCATESWITCH 替换步骤 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/

相关文章:

c# - SqlBulkCopy.WriteToServer()不断获取“连接已关闭”

java - 如何创建一个向客户端分发工作单元的服务器?

php - 我的 Codeigniter 安全删除数据库条目的方法

C# 循环、SQL 和检索信息

sql - TSQL 存储函数

C# 和 SQL 命令

sql - 从 UNION 中选择顶部...

vb.net - 是否有相当于 C#'s "使用 static 的 VB.NET?

Javascript GetElementsByClassName 变量位置

c# - 解析 RegEx 模式