我有大量的DataGridView,有940000行... ouch,通过解析csv文件填充,DataGridView有一个名为Sequence的列编号为1到940000.我试图做的是重新编号序列以便溢出对于DataGridView中的行数,为1到7000的序列。什么是重新排序序列列的最有效方法?
Using reader As New Microsoft.VisualBasic.FileIO.TextFieldParser(fileName)
reader.TextFieldType = FileIO.FieldType.Delimited
reader.SetDelimiters(",")
Dim currentRow As String()
Dim serial As String
Dim sequence As Integer = 0
Dim RollId As String
'pbUploadFile.Maximum = serialAmmount / quantityBreak
pbUploadFile.Maximum = serialAmmount
pbUploadFile.Step = 1
pbUploadFile.Value = 0
For i = 1 To serialAmmount / quantityBreak
For j = 1 To quantityBreak
Try
currentRow = reader.ReadFields()
serial = currentRow(0).ToString
sequence += 1
EnterDataIntoDatabase(serial, sequence, nextRollNumber, ddSelectPartNumber.Text)
pbUploadFile.Increment(1)
Catch ex As Microsoft.VisualBasic.FileIO.MalformedLineException
MsgBox("Code " & ex.Message & "is not valid and will be skipped check csv file")
End Try
Next j
sqlCmd = New SqlClient.SqlCommand("SELECT * FROM serials WHERE Sequence=@sequence AND RollNo=@rollNo ", sqlCon)
sqlCmd.CommandType = CommandType.Text
sqlCmd.Parameters.AddWithValue("@sequence", 1)
sqlCmd.Parameters.AddWithValue("@rollNo", nextRollNumber)
sqlCon.Open()
Dim readRollId As SqlClient.SqlDataReader = sqlCmd.ExecuteReader()
If readRollId.Read() Then
RollId = readRollId.Item("Code")
End If
sqlCon.Close()
UpdateAvailableRolls(ddSelectPartNumber.Text, nextRollNumber, RollId)
nextRollNumber += 1
UpdateRollNo(nextRollNumber)
sequence = 0
'pbUploadFile.Increment(1)
Next i
SaveFile()
End Using
答案 0 :(得分:2)
通常最好考虑如何使用数据以及何时确定如何做某事以及使用哪些工具来执行此操作。没人权利快|做大多数事情的有效方法。
那就是说,有一些糟糕的做事方式。使用DataGridView
作为数据容器似乎不明智(我实际上无法在代码中看到与DGV相关的任何内容)。 A)没有自动的方式让数据进入它 - 你必须编写代码来执行它,2)没有自动的方式让数据去其他地方 - 你必须编写代码来循环它和钓鱼数据退出。然后,所有数据都可能存储为字符串。
除了批量处理项目外,还有更多的事情要发生。以下将从CSV导入行,处理它们并将它们写回数据库(我使用的是MySql,但概念是相同的)。
首先,TextFieldParser
是一个非常方便的工具,但它有一个主要的缺点,它只返回字符串。如果CSV中包含价格,日期,布尔值等,则该类型将丢失。在许多情况下,CSVHelper将是更好的选择。
在这种情况下,由于数据的目的地是数据库,我会使用OleDB将CSV读入DataTable
,批量处理,然后将其发送到数据库。
<强> SCHEMA.INI 强>
OleDb包含一个文本文件驱动程序,可用于解析CSV。它可以根据前几行的上下文“猜测”数据类型,但您也可以定义它们。在CSV所在的文件夹/目录中,创建一个名为Schema.INI
的新文本文件。像这样定义CSV和列:
[Capitals.Csv]
ColNameHeader =真
格式= CSVDelimited
TextDelimiter =
DecimalSymbol =。
CURRENCYSYMBOL = $
Col1 =“国家”文字宽度254
Col2 =“首都”文字宽度254
Col3 =“人口”单一 Col4 =“Rank”整数
Col5 =“国庆日”日期
[...]
[...]
将是CSV的名称TextDelimiter="
Col#=
条目定义数据类型并可以覆盖名称。这允许您将CSV中名为“Foo”的列“映射”到数据库中名为“Bar”的列。连接字符串
要使用的连接字符串是:
ACEImportStr = "Provider=Microsoft.ACE.OLEDB.12.0;Data Source='{0}';Extended Properties='TEXT'"
Data Source
将是CSV和Schema.INI都存在的文件夹,'TEXT'元素告诉它使用Text驱动程序。使用文件夹名称填写空白:
ACEImportConnStr = String.Format(ACEImportConnStr, "C:\Temp")
OLEDB.12有时可能很挑剔,如果遇到问题,请改为使用Microsoft.Jet.OLEDB.4.0
。
现在,要加载数据,只需从CSV文件名(无文件夹)中选择:
Dim sSQL = "SELECT * FROM RandomOle.CSV"
...
Dim daSrc = New OleDbDataAdapter(sSQL, OleCSVConnstr)
rowsLoaded = daSrc.Fill(dtSample)
DataAdapter
将读取定义的模式,并在几秒钟内将CSV加载到数据表中。处理其他任务还有很多工作要做,但这就是概念。
Dim sSQL = "SELECT * FROM YOUR_CSVFILE_NAME.CSV"
Dim sw As New Stopwatch
Dim rowsLoaded As Int32
Dim rowsUpdated As Int32
sw.Start()
ACEImportConnStr = String.Format(ACEImportConnStr, "C:\Temp")
' create Destination MySQL conn, Src and Dest dataadapters,
' and a command builder (because I am lazy...and fallible)
Using mysqlCon As New MySqlConnection(MySQLConnStr),
daSrc As New OleDbDataAdapter(sSQL, ACEImportConnStr),
daDest As New MySqlDataAdapter("SELECT * FROM Sample", mysqlCon),
cb As New MySqlCommandBuilder(daDest)
' important!
daSrc.AcceptChangesDuringFill = False
dtSample = New DataTable
rowsLoaded = daSrc.Fill(dtSample)
' csv lacks an ID column - add it
Dim dc As New DataColumn("Id", GetType(Int32))
dc.DefaultValue = 1
dtSample.Columns.Add(dc)
dc.SetOrdinal(0)
' MY csv also lacks a BATCH column
dc = New DataColumn("Batch", GetType(Int32))
dc.DefaultValue = 1
dtSample.Columns.Add(dc)
dc.SetOrdinal(1)
' set the batch number
' each 5k rows == a batch
Dim batch As Int32 = 1
Dim counter As Int32 = 1
For Each dr As DataRow In dtSample.Rows
dr("Batch") = batch
counter += 1
If counter > 5000 Then
counter = 0
batch += 1
End If
Next
' now save the data to MySQL
mysqlCon.Open()
' inserting 250k rows takes a while,
' use a transaction
Using t As MySqlTransaction = mysqlCon.BeginTransaction
rowsUpdated = daDest.Update(dtSample)
t.Commit()
End Using
End Using
' show the IMPORT in a dgv
dgv1.DataSource = dtSample
dgv1.Columns("Id").Visible = False
' report
sw.Stop()
Console.WriteLine(sw.ElapsedMilliseconds)
原理很简单:由于数据绑定到数据库,因此尽快将数据转换为DataTable
。这里的诀窍是有2个DB提供者参与:OleDB读取csv和MySql以进行保存。
DataTable
时,所有行都设置为Unchanged
。 AcceptChangesDuringFill = False
将状态设置为Added
,以便MySql适配器可以插入这些行。EnterDataIntoDatabase
的作用,但您应该努力处理并准备DataTable
中的所有导入数据,然后立即更新所有数据。您似乎比批量或排序一堆行更多。上面的代码可以导入250k行,分配批号,并在1.2分钟内向MySql插入250k新行(几乎每秒3500行)。
如果批处理/序列发生器与CSV中的每个X行数相似,则您可以一次只加载7000行,设置值,保存该批处理,然后加载下一个7k行。这将限制任何时候加载的行数并减少应用程序使用的内存。我不确定它是否适用。
参考: