web-dev-qa-db-ja.com

SQLite Insertは非常に遅いですか?

最近、SQLiteについて読んで、試してみたいと思いました。 1つのレコードを挿入すると、大丈夫です。しかし、100を挿入すると5秒かかり、レコード数が増えると時間がかかります。何が間違っているのでしょうか? SQLite Wrapper (system.data.SQlite)を使用しています。

dbcon = new SQLiteConnection(connectionString);
dbcon.Open();

//---INSIDE LOOP

 SQLiteCommand sqlComm = new SQLiteCommand(sqlQuery, dbcon);

 nRowUpdatedCount = sqlComm.ExecuteNonQuery(); 

//---END LOOP

dbcon.close();
54

一括挿入の周りにBEGIN\ENDステートメントをラップします。 Sqliteはトランザクション用に最適化されています。

dbcon = new SQLiteConnection(connectionString);
dbcon.Open();

SQLiteCommand sqlComm;
sqlComm = new SQLiteCommand("begin", dbcon);
sqlComm.ExecuteNonQuery(); 
//---INSIDE LOOP

 sqlComm = new SQLiteCommand(sqlQuery, dbcon);

 nRowUpdatedCount = sqlComm.ExecuteNonQuery(); 

//---END LOOP
sqlComm = new SQLiteCommand("end", dbcon);
sqlComm.ExecuteNonQuery(); 
dbcon.close();
75
tidwall

すべての挿入(別名、一括挿入)を単一の トランザクション にラップしてみてください。

string insertString = "INSERT INTO [TableName] ([ColumnName]) Values (@value)";

SQLiteCommand command = new SQLiteCommand();
command.Parameters.AddWithValue("@value", value);
command.CommandText = insertString;
command.Connection = dbConnection;
SQLiteTransaction transaction = dbConnection.BeginTransaction();
try
{
    //---INSIDE LOOP
    SQLiteCommand sqlComm = new SQLiteCommand(sqlQuery, dbcon);
    nRowUpdatedCount = sqlComm.ExecuteNonQuery(); 
    //---END LOOP

    transaction.Commit();
    return true;
}
catch (SQLiteException ex)
{
    transaction.Rollback();
}

デフォルトでは、 SQLiteはトランザクション内のすべての挿入をラップします で、プロセスが遅くなります:

INSERTは本当に遅い-1秒あたり数ダースのINSERTしかできない

実際、SQLiteは平均的なデスクトップコンピューターで1秒あたり50,000以上のINSERTステートメントを簡単に実行します。ただし、1秒あたり数ダースのトランザクションしか実行しません。

(デフォルトでは)SQLiteは、トランザクションが完了する前にデータが実際にディスク表面に安全に保存されるまで実際に待機するため、トランザクション速度はディスクドライブ速度によって制限されます。そうすれば、突然電源が切れたり、OSがクラッシュした場合でも、データは安全です。詳細については、SQLiteのアトミックコミットについてお読みください。

デフォルトでは、各INSERTステートメントは独自のトランザクションです。ただし、複数のINSERTステートメントをBEGIN ... COMMITで囲むと、すべての挿入が単一のトランザクションにグループ化されます。トランザクションのコミットに必要な時間は、囲まれたすべての挿入ステートメントで償却されるため、挿入ステートメントごとの時間は大幅に短縮されます。

31
Jared Harley

トランザクションの作成はSQLiteの書き込みを遅らせる解決策であるとどこでも読んでいますが、コードを書き直し、SQLiteのすべての書き込みをトランザクションでラップするのは長くて苦痛です。

私ははるかにシンプルで安全で非常に効率的な方法を見つけました:(デフォルトで無効になっている)SQLite 3.7.0最適化を有効にします: Write-Ahead-Log(WAL) 。ドキュメントには、すべてのUNIX(つまりLinuxおよびOSX)およびWindowsシステムで動作することが記載されています。

どうやって ? SQLite接続を初期化した後、次のコマンドを実行するだけです。

PRAGMA journal_mode = WAL
PRAGMA synchronous = NORMAL

コードの実行速度が約600%速くなりました。テストスイートは4分ではなく38秒で実行できるようになりました:)

30
david_p

ADO.NETヘルプファイルSQLite.NET.chmの「SQLクエリの最適化」を参照してください。そのページのコード:

using (SQLiteTransaction mytransaction = myconnection.BeginTransaction())
{
  using (SQLiteCommand mycommand = new SQLiteCommand(myconnection))
  {
    SQLiteParameter myparam = new SQLiteParameter();
    int n;

    mycommand.CommandText = "INSERT INTO [MyTable] ([MyId]) VALUES(?)";
    mycommand.Parameters.Add(myparam);

    for (n = 0; n < 100000; n ++)
    {
      myparam.Value = n + 1;
      mycommand.ExecuteNonQuery();
    }
  }
  mytransaction.Commit();
}
8
Scott