Vb.net 在下一个例程中使用列表(字符串)会减慢速度



编辑:我已经放置了正在使用的完整 2 个子和 1 个函数。 我还在随着时间的推移而变慢的部分周围发表了评论。

在任何人提到FileHelpers之前,我不想使用第三方组件。

因此,我有一个CSV文件,350万行,我正在解析CSV的每一行并将其插入SQLite(非索引表(以保持速度。我还一次从 CSV 缓冲 100,000 行 - 世界一切都很好,但在我的循环中(在我将 100,000 行缓冲为字符串列表后,以下代码经过并相应地拆分每一行构建一个插入字符串并离开 - 每秒处理大约 1000 行 - 我可以忍受,但在几十万行之后, 它开始减慢到每秒 200 行左右。最终,在大约 600,000 行之后,它会爬行到 25 行,再往下爬,(不确定在什么时候(在 200 万 + 行之后会减慢到 10-15 行。我真的很想保持每秒 1000 行(如果可能的话,甚至改进它。

我省略了一些代码,一个 fixsquote 例程,它被调用来整理任何引号以及一个 IF THEN 语句来确定是否有引号并以不同的方式拆分它 - 对于这个特定的 350 万行 csv,没有任何引号,所以我只是想减少我在这里发布的代码量,以使其更清晰地阅读。

最初,我使用古老的数组来管理拆分,这是相同的,在 X 千行之后变慢了,但在互联网上看,似乎字符串列表会更好,所以我转换了几行代码来利用我的循环中的字符串列表,它并没有产生任何影响。我有一种感觉,虽然我似乎没有使用数组,但我对最终的减速感到困惑。有些东西要么没有被正确重用,要么可能是我不知道的堆栈或堆问题?

在批量插入期间我没有变慢 - 我可以完全删除插入并执行到 SQLITE,所以 SQLITE 不是问题。它与列表或字符串有关。我将尝试升级 .net 版本的建议 - 我在 4.6 上确实有这个,所以会把它升级到 4.7.1

******这是代码,也许有人可以发现一些明显的东西。

Private Sub CSVImport
Dim SQLStr As New Text.StringBuilder
Dim BigSQLStr As New Text.StringBuilder
Dim Comma As String = ""
Dim FirstInsertStr As New Text.StringBuilder
Dim BufferT As Integer = 0
Try

If IO.File.Exists(FileName) = True Then

Dim C As Integer
Dim line As String

FirstInsertStr.Clear()
FirstInsertStr.Capacity = 0
FirstInsertStr.Append("INSERT INTO " & Chr(34) & DestinationTableName & Chr(34))
FirstInsertStr.Append(" (" & Chr(34) & "LON" & Chr(34))
FirstInsertStr.Append(", " & Chr(34) & "LAT" & Chr(34))
FirstInsertStr.Append(", " & Chr(34) & "NUMBER" & Chr(34))
FirstInsertStr.Append(", " & Chr(34) & "STREET" & Chr(34))
FirstInsertStr.Append(", " & Chr(34) & "UNIT" & Chr(34))
FirstInsertStr.Append(", " & Chr(34) & "CITY" & Chr(34))
FirstInsertStr.Append(", " & Chr(34) & "DISTRICT" & Chr(34))
FirstInsertStr.Append(", " & Chr(34) & "REGION" & Chr(34))
FirstInsertStr.Append(", " & Chr(34) & "POSTCODE" & Chr(34))
FirstInsertStr.Append(", " & Chr(34) & "ADDRESSIO_ID" & Chr(34))
FirstInsertStr.Append(", " & Chr(34) & "HASH" & Chr(34))
FirstInsertStr.Append(") VALUES (")

BufferT = 0
BigSQLStr.Clear()
BigSQLStr.Capacity = 0
' Create new StreamReader instance with Using block.
Using reader As IO.StreamReader = New IO.StreamReader(FileName)
' Read one line from file
line = reader.ReadLine ' first line in headers so ignore
Do Until line = Nothing
' Stop
Dim BufferRead As New List(Of String)
Dim BufferLoad As Integer = 0
Do Until BufferLoad = 100000
line = reader.ReadLine
If line = Nothing Then
Exit Do
End If
BufferRead.Add(line)
BufferLoad += 1
Loop
Dim Z As Integer = 0
For Z = 0 To BufferLoad - 1
BufferT += 1
Comma = ""
' ************** I BELIEVE THE SLOWDOWN IS WITHIN HERE, FAST AT FIRST, THEN SLOWS DOWN AFTER 30k RECORDS OR SO **********                           
Dim objFields2 As New List(Of String)
If BufferRead(Z).Contains(Chr(34)) = True Then
BufferRead(Z) = FixsQuote(BufferRead(Z))
objFields2.AddRange(Split(BufferRead(Z), ",", Chr(34), True))
Else
objFields2.AddRange(BufferRead(Z).Split(","))
End If

With SQLStr
.Clear()
.Capacity = 0
For C = 0 To objFields2.Count - 1
If C > 11 Then
Exit For ' we only ever want the first 11 fields.
End If
If C > 0 Then
Comma = ","
End If
If IsDBNull(objFields2(C)) = False Then
If objFields2(C).Contains(Chr(34)) = True Then
If objFields2(C).Replace(Chr(34), "").Length > 0 Then
.Append(Comma & "'" & FixsQuote(objFields2(C).Replace(Chr(34), "")) & "'")
Else
.Append(Comma & "Null")
End If
Else
If objFields2(C).Length > 0 Then
.Append(Comma & "'" & FixsQuote(objFields2(C)) & "'")
Else
.Append(Comma & "Null")
End If
End If
Else
.Append(Comma & "Null")
End If
Next
BigSQLStr.Append(FirstInsertStr.ToString)
BigSQLStr.Append(.ToString)
BigSQLStr.Append(");")
' Now Insert what we have
If BufferT = 1000 Then
Using OleCMD As New SQLite.SQLiteCommand(BigSQLStr.ToString, AddressesIOSQLDB)
OleCMD.CommandTimeout = 0
OleCMD.ExecuteNonQuery()
End Using
BigSQLStr.Clear()
BigSQLStr.Capacity = 0
BufferT = 0
End If

End With

objFields2.Clear()
objFields2 = Nothing
Next
BufferRead.Clear()
' ****************** end of what i believe is the slow down ****************
Loop
If BufferT > 0 Then
Try
Using OleCMD As New SQLite.SQLiteCommand(BigSQLStr.ToString, AddressesIOSQLDB)
OleCMD.CommandTimeout = 0
OleCMD.ExecuteNonQuery()
End Using
Catch ex As Exception
Stop
End Try
BufferT = 0
End If
End Using
End If

Catch ex As Exception
Stop
End Try

BigSQLStr.Clear()
BigSQLStr.Capacity = 0
FirstInsertStr.Clear()
FirstInsertStr.Capacity = 0
SQLStr.Clear()
SQLStr.Capacity = 0
End Sub

Private Function FixsQuote(ByVal s As String) As String
Return s.Replace("'", "''")
End Function

Private Function Split(
ByVal expression As String,
ByVal delimiter As String,
ByVal qualifier As String,
ByVal ignoreCase As Boolean) As List(Of String)
Dim _Statement As String = String.Format("{0}(?=(?:[^{1}]*{1}[^{1}]*{1})*(?![^{1}]*{1}))", Regex.Escape(delimiter), Regex.Escape(qualifier))
Dim _Options As RegexOptions = RegexOptions.Compiled Or RegexOptions.Multiline
If ignoreCase Then _Options = _Options Or RegexOptions.IgnoreCase
Dim _Expression As Regex = New Regex(_Statement, _Options)
Return _Expression.Split(expression).ToList
End Function

我不敢相信这一点,但是在查看了 TnTinMn 的建议(这使得实际转换的转换花费不到一秒钟的时间以及删除 BigSQLStr 和 SQLStr 文本字符串生成器(因为我现在正在执行事务中的每个插入,我每秒泵入 20,000 条记录。吹走了小伙子,吹走了。非常感谢大家让我解析我的代码,而不是认为字符串生成器是一切的解决方案。从现在开始,我将我的大插入放入事务中,并在可能的情况下离开文本字符串构建器,现在我简直不敢相信(我已经用数据库中的记录计数验证了它(。

相关内容

  • 没有找到相关文章

最新更新