【问题标题】:Out of memory error when adding rows to a datatable in vb.net将行添加到 vb.net 中的数据表时出现内存不足错误
【发布时间】:2017-05-31 13:37:03
【问题描述】:

我最终尝试使用SqlBulkCopy 将文件中的行插入到 SQL Server 数据库中。我的代码如下。

当我尝试向数据表中添加太多行时,就会出现问题。我不确定限制是多少,但我的文件有 500 万行,并且我得到了一个 OutOfMemoryException 就行了:

newRow.ItemArray = objFields.ToArray()

所以我认为这与数据表的限制有关。

有没有一种方法可以逐步添加行并一次插入一些行,或者我在这里做错了什么可以更改?

这个过程确实适用于较小的文件。

谢谢

Public Sub bulk_insert(file_name, delimiter, table_name)

        ' create a data table from the file
        ' ---------------------------------
        Dim lines = IO.File.ReadAllLines(file_name)
        Dim tbl = New DataTable
        Dim colCount = lines.First.Split(delimiter).Length

        ' add the correct number of columns to the table
        ' ----------------------------------------------
        For i As Int32 = 1 To colCount
            tbl.Columns.Add(New DataColumn("Column_" & i, GetType(String)))
        Next

        ' add the lines to the data table
        ' -------------------------------
        For Each line In lines
            Dim objFields = From field In line.Split(delimiter) Select CType(field, Object)
            Dim newRow = tbl.Rows.Add()
            newRow.ItemArray = objFields.ToArray()
        Next

        ' create a connection to the database
        ' -----------------------------------
        Dim myConn = New SqlConnection(Main.this_page.sql_connection_string)

        ' start the Bulk Copy
        Dim SqlBulkCopy = New SqlBulkCopy(myConn)
        SqlBulkCopy.BatchSize = 10000
        SqlBulkCopy.BulkCopyTimeout = 10000

        ' open the connection
        ' -------------------
        myConn.Open()

        ' perform the copy
        ' ----------------
        SqlBulkCopy.DestinationTableName = table_name
        SqlBulkCopy.WriteToServer(tbl)

        ' cloe the connection
        ' -------------------
        myConn.Close()

    End Sub

编辑:经过测试发现报错时,行数为2097152

编辑:由于我不想回答我自己的问题,也无法将其放在评论中,因此我根据以下 the_lotus 提供的答案将我的结果包含在下面。下面的代码解决了这个问题:

Public Sub bulk_insert(file_name, delimiter, table_name)

        ' create a connection to the database
        ' -----------------------------------
        Dim myConn = New SqlConnection(Main.this_page.sql_connection_string)
        ' open the connection
        ' -------------------
        myConn.Open()

        ' create a data table from the file
        ' ---------------------------------
        Dim lines = IO.File.ReadAllLines(file_name)
        Dim tbl = New DataTable
        Dim colCount = lines.First.Split(delimiter).Length

        ' add the correct number of columns to the table
        ' ----------------------------------------------
        For i As Int32 = 1 To colCount
            tbl.Columns.Add(New DataColumn("Column_" & i, GetType(String)))
        Next

        Dim x As Integer = 0
        While x < lines.Count - 1

            ' clear the data table
            ' --------------------
            tbl.Clear()

            ' add the lines to the data table in 1M row increments
            ' ---------------------------------------------------
            If x + 1000000 > lines.Count - 1 Then
                For y = x To lines.Count - 1
                    Dim objFields = From field In lines(y).Split(delimiter) Select CType(field, Object)
                    Dim newRow = tbl.Rows.Add()
                    newRow.ItemArray = objFields.ToArray()
                Next
                x = lines.Count - 1
            Else
                For y = x To x + 1000000
                    Dim objFields = From field In lines(y).Split(delimiter) Select CType(field, Object)
                    Dim newRow = tbl.Rows.Add()
                    newRow.ItemArray = objFields.ToArray()
                Next
                x += 1000000
            End If


            ' start the Bulk Copy
            Dim SqlBulkCopy = New SqlBulkCopy(myConn)
            SqlBulkCopy.BatchSize = 1000000
            SqlBulkCopy.BulkCopyTimeout = 1000

            ' perform the copy
            ' ----------------
            SqlBulkCopy.DestinationTableName = table_name
            SqlBulkCopy.WriteToServer(tbl)

        End While

        ' cloe the connection
        ' -------------------
        myConn.Close()

    End Sub

【问题讨论】:

  • 你自己回答了你的问题......加载前 100 个然后做你的东西,然后加载下一个 100 等等
  • 但是如何释放内存呢?
  • 数据表限制为 160 亿行(但这可能基于单个 int 列)。一个问题是您还将整个文件读入内存。使用类似 CSVHelper 的库
  • 你知道什么是内存吗? webopedia.com/TERM/R/RAM.html 内存是磨损数据存储在您的计算机内存有限且仅分配给您的应用程序的一定数量,因此加载超过 500 万行数据您的计算机无法处理使用那么多内存.. 想想看就像一小杯水。你不能在里面装1L。但是你可以装 50 毫升喝下去,再装 50 毫升喝到 1 升
  • 对这个任务使用 DataTable 是错误的方法。 DataTable 所做的只是为 SqlBulkCopy 实例提供一个IDataReader。编写自己的 IDataReader 实现来解析文件并将数据提供给 SqlBulkCopy 会更好地为您服务。

标签: sql-server vb.net datatable


【解决方案1】:

您的内存快用完了...您的数据在行和 tbl 中重复。您已经指定了 10000 的 BatchSize,您不需要加载更多。

我愿意:

  • 一次读一行
  • 在你的tbl中添加该行的信息
  • 当您的 tbl 中有 BatchSize 数量的数据时,将它们发送到数据库
  • 清除您的 tbl 数据并继续,直到文件完成

如果您有 500 万行并且每行有 100 个字符的数据。那是您的 lines 变量中的 500mb 数据。然后你在 tbl 中复制这些数据,DataTable 必须有每个数据点和行的额外信息。

【讨论】:

  • @user2721815 很快!很高兴它有帮助。
猜你喜欢
  • 2020-01-30
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-12-30
  • 2015-06-14
相关资源
最近更新 更多