SQLite3は、同じDBから読み書きする複数のプロセスによる同時アクセスを安全に処理しますか?それにプラットフォームの例外はありますか?
SQLite3は、同じDBから読み書きする複数のプロセスによる同時アクセスを安全に処理しますか?それにプラットフォームの例外はありますか?
回答:
これらの同時アクセスのほとんどが読み取り(SELECTなど)である場合、SQLiteはそれらを非常にうまく処理できます。ただし、同時に書き込みを開始すると、ロックの競合が問題になる可能性があります。SQLiteエンジン自体は非常に高速であり、競合を最小限に抑えるために多くの巧妙な最適化が行われているため、ファイルシステムの速度に大きく依存します。特にSQLite 3。
ほとんどのデスクトップ/ラップトップ/タブレット/電話アプリケーションでは、同時実行性が十分でないため、SQLiteは十分に高速です。(FirefoxはSQLiteをブックマーク、履歴などに幅広く使用しています)
サーバーアプリケーションの場合、ある日以前に、典型的なシナリオ(ブログ、フォーラムなど)では、1日あたり10万ページ未満のページビューであればSQLiteデータベースで完全に処理できると誰かが言っていました。実際、最新のディスクとプロセッサを使用すると、95%のWebサイトとWebサービスがSQLiteで正常に動作します。
本当に高速な読み取り/書き込みアクセスが必要な場合は、インメモリSQLiteデータベースを使用してください。RAMはディスクより数桁高速です。
はい、SQLiteは並行性を適切に処理しますが、パフォーマンスの観点からは最善ではありません。私が言うことができることから、それに例外はありません。詳細はSQLiteのサイトにあります:https : //www.sqlite.org/lockingv3.html
このステートメントは興味深いものです。「ページャーモジュールは、変更がすべて同時に発生するか、すべての変更が発生しないか、どれも発生しないこと、2つ以上のプロセスが同時に互換性のない方法でデータベースにアクセスしようとしないことを確認します」
はい、そうです。理由を理解しましょう
SQLiteの単一トランザクション内のすべての変更は完全に発生するか、まったく発生しない
このようなACIDサポートと同時の読み取り/書き込みは、2つの方法で提供されます。いわゆるジャーナリング(「古い方法」と呼びます)または先読みログ(「新しい方法」と呼びます)を使用します。
このモードでは、SQLiteはDATABASE-LEVEL ロックを使用します。これは理解すべき重要なポイントです。
つまり、何かを読み書きする必要があるときは常に、最初にENTIREデータベースファイルのロックを取得します。複数のリーダーが共存し、並行して何かを読むことができます
書き込み中は、排他ロックが取得され、他のロックは取得されませんプロセスが同時に読み取り/書き込みを行っていないため、書き込みは安全です。
これが理由です、ここで彼らはSQLiteの実装言っているシリアル化可能トランザクションを
毎回データベース全体をロックする必要があり、誰もが書き込みの同時実行を処理するプロセスを待機するため、このような同時書き込み/読み取りのパフォーマンスはかなり低い
データベースファイルに何かを書き込む前に、SQLiteはまず変更するチャンクを一時ファイルに保存します。データベースファイルへの書き込み中にクラッシュが発生した場合、この一時ファイルが取得され、変更が元に戻されます。
この場合、すべての書き込みは一時ファイルに追加されます(先書きログ)にこのファイルは定期的に元のデータベースとマージされます。SQLiteが何かを検索するとき、最初にこの一時ファイルをチェックし、何も見つからない場合はメインデータベースファイルを続行します。
その結果、リーダーはライターと競合せず、パフォーマンスはオールドウェイと比較してはるかに優れています。
SQliteは基盤となるファイルシステムのロック機能に大きく依存しているため、注意して使用する必要があります。詳細はこちら
また、特にジャーナルモードでは、データベースがロックされてエラーが発生する可能性が高いため、このエラーを考慮してアプリを設計する必要があります。
WAL(ログ先行書き込み)モードについて言及した人はいません。トランザクションが適切に編成され、WALモードがオンになっていることを確認してください。更新が行われている間、人々が物事を読んでいる間、データベースをロックしておく必要はありません。
唯一の問題は、ある時点でWALをメインデータベースに再統合する必要があることです。これは、データベースへの最後の接続が閉じたときに行われます。非常にビジーなサイトでは、すべての接続が閉じるまでに数秒かかる場合がありますが、1日あたり10万ヒットは問題になりません。
database is locked
エラーがライターによって発生することは言及する価値がある
2019年には、2つの新しい同時書き込みオプションがまだリリースされていませんが、別々のブランチで利用できます。
通常の "wal"モードに対するこのジャーナルモードの利点は、ライターが1つのwalファイルへの書き込みを続行し、他のファイルがチェックポイントされていることです。
BEGIN CONCURRENT-詳細なドキュメントへのリンク
BEGIN CONCURRENTの強化により、データベースが「wal」または「wal2」モードの場合、複数のライターが書き込みトランザクションを同時に処理できますが、システムはまだCOMMITコマンドをシリアル化しています。
"BEGIN CONCURRENT"で書き込みトランザクションが開かれると、データベースの実際のロックはCOMMITが実行されるまで延期されます。つまり、BEGIN CONCURRENTで開始されたトランザクションはいくつでも同時に進行できます。システムは、オプティミスティックページレベルロックを使用して、競合する並行トランザクションがコミットされるのを防ぎます。
一緒に、それらはbegin-concurrent-wal2またはそれぞれ別の独自のブランチに存在します。
begin concurrent
。
SQLiteには、データベースレベルでリーダー/ライターロックがあります。複数の接続(異なるプロセスが所有している可能性があります)は、同じデータベースから同時にデータを読み取ることができますが、データベースに書き込むことができるのは1つだけです。
SQLiteは無制限の数の同時リーダーをサポートしますが、同時に使用できるライターは1つだけです。多くの場合、これは問題ではありません。ライターがキューに入りました。各アプリケーションは、データベースの作業をすばやく実行して続行します。ロックは数十ミリ秒以上続きません。しかし、より多くの同時実行性を必要とするアプリケーションがいくつかあり、それらのアプリケーションは別のソリューションを探す必要があるかもしれません。- SQLiteの@ SQLite.orgのための適切な使用方法
読み取り/書き込みロックは、独立したトランザクション処理を可能にし、データベースレベルで排他ロックと共有ロックを使用して実装されます。
接続がデータベースに対して書き込み操作を実行する前に、排他ロックを取得する必要があります。排他ロックが取得されると、他の接続からの読み取り操作と書き込み操作の両方が、ロックが再び解放されるまでブロックされます。
SQLiteには、最大同時実行性を保証するために、書き込み操作中にデータベースをできるだけ遅くロックするのに役立つロックテーブルがあります。
初期状態はUNLOCKEDであり、この状態では、接続はまだデータベースにアクセスしていません。プロセスがデータベースに接続され、トランザクションがBEGINで開始された場合でも、接続はまだUNLOCKED状態です。
UNLOCKED状態の後、次の状態はSHARED状態です。データベースからデータを読み取ることができる(書き込むことはできない)ためには、SHAREDロックを取得して、接続が最初にSHARED状態に入る必要があります。複数の接続がSHAREDロックを同時に取得および維持できるため、複数の接続が同じデータベースから同時にデータを読み取ることができます。ただし、1つのSHAREDロックのみが解放されないままである限り、どの接続もデータベースへの書き込みを正常に完了できません。
接続がデータベースへの書き込みを希望する場合、最初にRESERVEDロックを取得する必要があります。
一度にアクティブにできるのは1つのRESERVEDロックだけですが、複数のSHAREDロックは1つのRESERVEDロックと共存できます。RESERVEDがPENDINGと異なるのは、RESERVEDロックがあるときに新しいSHAREDロックを取得できる点です。- ファイルロックと同時実行でSQLiteのバージョン3 @ SQLite.org
接続がRESERVEDロックを取得すると、データベース変更操作の処理を開始できますが、これらの変更は実際にディスクに書き込まれるのではなく、バッファーでのみ実行できます。読み出しコンテンツに加えられた変更は、メモリバッファに保存されます。接続が変更(またはトランザクション)を送信する場合、RESERVEDロックをEXCLUSIVEロックにアップグレードする必要があります。ロックを取得するには、まずロックを持ち上げて保留中のロックにする必要があります。
PENDINGロックは、ロックを保持しているプロセスができるだけ早くデータベースに書き込むことを望んでおり、現在のすべてのSHAREDロックがクリアされるのを待っているため、排他ロックを取得できることを意味します。PENDINGロックがアクティブな場合、データベースに対する新しいSHAREDロックは許可されませんが、既存のSHAREDロックは続行できます。
データベースファイルに書き込むには、排他ロックが必要です。ファイルで許可される排他ロックは1つだけで、他のどのロックも、排他ロックと共存することはできません。同時実行性を最大化するために、SQLiteはEXCLUSIVEロックが保持される時間を最小化するように機能します。- ファイルロックと同時実行でSQLiteのバージョン3 @ SQLite.org
したがって、SQLiteがサポートしていないという理由だけで、同じDBに書き込む複数のプロセスによる同時アクセスをSQLiteが安全に処理すると言えるかもしれません。あなたは得るでしょうSQLITE_BUSY
かSQLITE_LOCKED
、それが再試行制限を打つときに、第2の作家のため。
このスレッドは古いですが、sqliteで実行したテストの結果を共有するのは良いことだと思います。EXCLUSIVEロックとタイムアウトに設定されたトランザクション内で、ステートメントSELECTとUPDATE sqlコマンドを実行するPythonプログラムの2つのインスタンスを実行しました(異なるプロセスは同じプログラム)。ロックを取得するのに10秒かかり、結果は苛立たしいものでした。すべてのインスタンスは10000ステップループで実行されました。
sqliteがトランザクションに排他ロックを許可した場合でも、実際に実行されたサイクルの合計数は20 000以下ではありませんでした(両方のプロセスでカウントされた単一カウンターの合計反復数)。Pythonプログラムはほとんど単一の例外をスローしませんでした(20回の実行の選択中に1回だけ)。テスト時のsqliteリビジョンは3.6.20で、Python v3.3 CentOS 6.5でした。私の意見では、この種の仕事のためのより信頼できる製品を見つけるか、sqliteへの書き込みを単一の一意のプロセス/スレッドに制限する方が良いです。
with con
で十分だと信じ込ませているにもかかわらずです。