SQL 和 VB.net winform 的批量更新概念

Posted

技术标签:

【中文标题】SQL 和 VB.net winform 的批量更新概念【英文标题】:Bulk Updates Concept for SQL and VB.net winform 【发布时间】:2015-05-05 00:55:27 【问题描述】:

对于 SQL Server 2008+ 中大型表的批量更新,我将不胜感激。

目前我有一个包含 10,000 行和 160 列的表。此表会非常频繁地更新,每行有 1 到 100+ 列更改,具体取决于流程。使用DataAdapter 使用“标准新手”表更新非常缓慢且不合适。

任务是找到更快的方法。我已经尝试使用批量大小微调DataAdapter.Update,不管更繁重的更新需要 10-15 秒。同时SqlBulkCopy在(球场)1-3秒内输入整个表。当更新过程在一个过程中发生 30-50 次时,10s-15s 加起来!

作为互联网自我思考,我的经验存在差距,但是我可以想到有两种可能性,它们可能会更好地完成更新任务。

    从数据库中转储表格内容并使用SqlBulkcopy重新填充表格。

    使用存储过程和通过合并 SQL 语句传递给它的表。

主要问题是数据安全,尽管这是一个本地单用户应用程序,但需要一种方法来处理错误回滚。据我了解,转储和替换会更简单,但可能更容易丢失数据?存储过程的设置范围要大得多,因为更新语句必须单独键入所有更新列并为更改进行维护。除非有一个“更新 *”声明:)。

为了保持简短,我只想将其保持在概念级别,但会感谢任何不同的想法或链接和建议。

编辑更多信息: 该表只有一个索引,即 ID 列。它是将传入(和更改)数据存储到简单数据表的简单过程。并且更新可以是 1 行到 1000 行之间的任何位置。该程序经常将信息存储到数据库中,并且可以是部分或几乎所有列。为每个更新构建一个存储过程是不可能的,因为我不知道哪些数据将被更新,你可以说所有的列都将被更新(除了 ID 列和一些“硬”数据列)它取决于更新输入是什么。因此,除非我每次都列出几乎所有列,否则没有对特定列的更新进行微调。在这种情况下,一个存储过程可以做到这一点。

我认为问题在于对数据库的“调用”次数是使用当前数据适配器方法进行的。

编辑: 3 关于一个暂存表,我将数据批量复制到其中,然后让存储过程进行更新。这不会减少 SQL 流量吗?我认为这是数据适配器更新的问题。

编辑:在此线程的答案中发布了概念 1 的尝试。

谢谢

【问题讨论】:

你能详细说明一下表格的结构和更新吗?表上有哪些索引(尤其是聚集索引)?这些更新的确切频率是多少,为什么? 【参考方案1】:

删除表格并使用批量复制重新加载整个内容不是正确的方法。

我建议为每个更新表的进程创建一个存储过程。该过程应仅将需要为该特定进程更新的列作为输入,然后运行标准 SQL 更新命令来更新指定行上的这些列。如果可能,请尝试在用于查找需要更新的记录的列上建立索引。

或者,根据您使用的 .Net 框架版本,如果您不想维护完整的存储过程列表,您可以尝试使用实体框架。

【讨论】:

用于查找行的列已编入索引。不幸的是,更新可能包含 1 到 120 列的更新,所以我会在每个更新命令中命名几乎所有更新。【参考方案2】:

我编写了以下模型来转储表中的所有行,将内存中的表批量复制到 sql 暂存表中,然后将数据移回原始表中。因此,通过更新该表中的数据。

耗时 1.1 到 1.3 秒

与更新所需的 10 到 15 秒相比,这无疑是一个非常有吸引力的时间。我已将临时表的截断代码放在顶部,以便数据库中始终存在一份信息副本。虽然原始表在该过程完成之前不会有更新的信息。

与这种方法相关的陷阱是什么?我能对他们做些什么?我必须说明该表不可能超过 10000 行,因此该过程将起作用。

 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()

        Catch ex As Exception

            ErrMess = "ERROR - occured at " & ESTP & " " & ex.ToString
            Call WriteError()
            Call ViewError()

        End Try

【讨论】:

以上是关于SQL 和 VB.net winform 的批量更新概念的主要内容,如果未能解决你的问题,请参考以下文章

VB.NET Winform的一些功能实现

VB.NET WinForm获取运行程序用户名

VB.NET(WinForms)中带参数的安全线程池队列

VB.NET如何在winform中“刷新”数据DbContext

将 VB.NET 2.0 Winform 迁移到 3.5 WPF

所有循环崩溃winforms vb.net?