使用VB.NET的SQLite数据库的性能问题

使用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

我正在将数据表插入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 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个记录。