使用VB.NET的SQLite数据库的性能问题
我正在将数据表插入SQLite数据库。我就是这样做的。 首先,我使用getdata函数获取数据并将其插入datatable,然后使用For Each循环生成insert命令并执行它。我有50000条记录,运行需要30分钟。 请引导合适的方法。这是代码使用VB.NET的SQLite数据库的性能问题,vb.net,sqlite,Vb.net,Sqlite,我正在将数据表插入SQLite数据库。我就是这样做的。 首先,我使用getdata函数获取数据并将其插入datatable,然后使用For Each循环生成insert命令并执行它。我有50000条记录,运行需要30分钟。 请引导合适的方法。这是代码 Dim xtable As DataTable = getdata("select * from tablename") Dim str As String = Nothing For Each r As DataRow In
Dim xtable As DataTable = getdata("select * from tablename")
Dim str As String = Nothing
For Each r As DataRow In xtable.Rows ''''HERE IT WILL TAKE TOO MUCH TIME
str = str & ("insert into tablename values(" & r.Item("srno") & "," & r.Item("name"));")
Next
EXECUTEcmd(str)
Public Function getdata(ByVal Query As String) As DataTable
connectionString()
Try
Dim mds As New DataTable
Dim mycommand As New SQLiteCommand(DBConn)
mycommand.CommandText = Query
Dim reader As SQLiteDataReader = mycommand.ExecuteReader()
mds.Load(reader)
Return mds
Catch ex As Exception
MsgBox("DB Error", vbCritical, "")
MsgBox(Err.Description)
Return Nothing
End Try
End Function
Public Sub EXECUTEcmd(ByVal selectcmd As String)
Using cn = New SQLiteConnection(conectionString)
cn.Open()
Using transaction = cn.BeginTransaction()
Using cmd = cn.CreateCommand()
cmd.CommandText = selectcmd
cmd.ExecuteNonQuery()
End Using
transaction.Commit()
End Using
cn.Close()
End Using
End Sub
此处连接字符串为:
conStr = "Data Source=" & dbpath & ";Version=3;Compress=True; UTF8Encoding=True; PRAGMA journal_mode=WAL; cache=shared;"
使用stringbuilder构建字符串,而不是字符串连接
Dim strB As StringBuilder = New StringBuilder(100 * 50000)
For Each r As DataRow In xtable.Rows
strB.AppendLine($"insert into tablename values({r.Item("srno")},{r.Item("name")});")
Next
无法在.net中更改字符串。每次创建新字符串时,VB都必须将旧字符串中的所有内容复制到新字符串中,并添加所需的新位。如果每个insert语句都是100字节,这意味着它复制100字节,然后添加100,然后复制200字节,然后添加100,然后复制300字节,然后是400字节,然后是500字节。当它完成10个字符串时,已经完成了5.5kB的复制。到完成50000个字符串时,它已经复制了125G的数据。怪不得这么慢
始终使用StringBuilder构建大量字符串
-
由于任务的性质,我愿意忽略sql注入攻击,但是请阅读-您永远不应该将值连接到sql中,作为生成具有某种不同效果的sql的一种方法
整个练习最好使用伪代码:
Dim sel as New SQLiteCommand("SELECT a, b FROM table", conn)
Dim ins as New SQLiteCommand("INSERT INTO table VALUES(:a, :b)", conn)
ins.Parameters.Add("a" ...)
ins.Parameters.Add("b" ...)
Dim r = sel.ExecuteReader()
While r.Read()
ins.Parameters("a") = r.GetString(0)
ins.Parameters("b") = r.GetString(1)
ins.ExecuteNonQuery()
End While
也就是说,通过从数据集中一次读取一行,然后在插入中一次插入一行,可以最小化内存;insert命令准备一次,您只需更改参数值,执行它,再次更改它们,执行它。。。这就是参数化查询的设计目的,当有人将SQL放入你的变量时,它可以阻止你的应用程序被黑客攻击,甚至当你有一个叫O'Grady的人时,它可以停止崩溃。也许你必须像这样重构你的代码:
Dim xtable As DataTable = getdata("select * from tablename")
Using cn = New SQLiteConnection(conectionString)
cn.Open()
Using transaction = cn.BeginTransaction()
Try
Using cmd = cn.CreateCommand()
cmd.Transaction = transaction
For Each r As DataRow In xtable.Rows ''''HERE IT WILL TAKE TOO MUCH TIME
cmd.CommandText = "insert into tablename values(" & r.Item("srno") & "," & r.Item("name") & ")"
cmd.ExecuteNonQuery()
Next
End Using
transaction.Commit()
Catch ex As Exception
transaction.Rollback()
End Try
End Using
End Using
Public Function getdata(ByVal Query As String) As DataTable
connectionString()
Try
Dim mds As New DataTable
Dim mycommand As New SQLiteCommand(DBConn)
mycommand.CommandText = Query
Dim reader As SQLiteDataReader = mycommand.ExecuteReader()
mds.Load(reader)
Return mds
Catch ex As Exception
MsgBox("DB Error", vbCritical, "")
MsgBox(Err.Description)
Return Nothing
End Try
End Function
不要连接一个可能的巨大字符串,而是将所有插入内容包装到一个事务中,如上文所述。这将减少使用的内存,并使sqlite运行更快。SELECT和INSERT语句中的表是否相同?否,两者都是不同的表…从一个表中获取数据并将其插入到另一个表中,或者将数据从SQLServer导入sqlite,一次有50000条记录。有没有更好的解决方案来完成同样的任务。上面的代码可以工作,但当我在没有for循环的情况下完成时。它仍然非常缓慢。使用cmd=cn.CreateCommand cmd.Transaction=Transaction cmd.CommandText=sqlstring cmd.ExecuteNonQuery End使用。此sqlstring具有50000个记录。