6

私はDelphiXE2DISQLitev3(基本的にSQLite3の移植版)と一緒に使用しています。同時書き込みがないことを除いて、SQLite3のすべてが大好きです。特に、このプロジェクトではマルチスレッドに大きく依存しています:(

私のプロファイラーは、それについて何かをする必要があることを明らかにしたので、このアプローチを使用することにしました。

  1. DBにレコードを挿入する必要があるときはいつでも、INSERTを実行する代わりにwrite、特別なフォーラーでSQLクエリを実行します。

    WriteToFile_Inline(SPECIAL_FOLDER_PATH + '\' + GUID, FileName + '|' + IntToStr(ID) + '|' + Hash + '|' + FloatToStr(ModifDate) + '|' + ...);

  2. 毎分timer起動する(メインアプリスレッドに)を追加し、これらのファイルを解析してから、トランザクションを使用してクエリを挿入します。

  3. 最後にそれらの一時ファイルを削除します。

その結果、パフォーマンスが500%向上しました。さらに、この手法はACIDSPECIAL_FOLDER_PATHです。停電後はいつでもスキャンして、見つけたINSERTを実行できます。

良い結果にもかかわらず、私は使用された方法にあまり満足していません(控えめに言ってもハックです)、高速ルックアップアクセス、スレッドセーフ、ACIDリストのようなジェネリックがあれば、これははるかにクリーン(そしておそらくより速い?)

だから私の質問は:Delphi XE2についてそのようなことを知っていますか?


PS。上記のコードを読んでいる多くの人がショックを受けていると信じており、この時点で私を侮辱し始めます!私のゲストになってください、しかしあなたがより良い(すなわちより速い)ACIDアプローチを知っているなら、あなたの考えを共有してください

4

3 に答える 3

5

挿入物をキューに送信して、挿入物を再配置し、プリペアドステートメントを介してそれらを結合するというアイデアは非常に優れています。メインスレッドまたは別のスレッドでタイマーを使用するかどうかはあなた次第です。ロックを回避します。

トランザクションを使用することを忘れないでください。その後、たとえば100/1000挿入ごとにコミットします。

SQLite3を使用した高性能については、たとえばこのブログ記事(および以下の図)を参照してください。

速度比較

この図では、最高のパフォーマンス(ファイルオフ)は次の要素から得られます。

  • PRAGMA synchronous = OFF
  • プリペアドステートメントの使用
  • トランザクション内
  • WALモードの場合(特に同時実行モードの場合)

ページサイズやジャーナルサイズを変更することもできますが、上記の設定が最適です。https://stackoverflow.com/search?q=sqlite3+performanceを参照してください

バックグラウンドスレッドを使用したくない場合は、WALがオンになっていることを確認し、ステートメントを準備し、バッチを使用して、プロセスを再グループ化して、SQLite3ロックをできるだけ早く解放します。

最高のパフォーマンスは、mORMotの場合と同様に、クライアントサーバーレイヤーを追加することで実現されます。

于 2013-01-06T09:54:46.883 に答える
3

ファイルを使用して、永続性を備えた非同期ジョブキューを編成しました。これにより、 (レコードグループ)アプローチを回避one-by-oneして使用し、レコードを挿入できます。batch比較one-by-onebatch

  • 最初は各レコードに対して自動コミットモード(おそらく)で動作し、2番目はバッチを単一のトランザクションにラップして最大のパフォーマンス向上をもたらします。
  • 最初にレコードを挿入する必要があるたびにINSERTコマンドを準備し(おそらく)、2番目にバッチごとに1回、2番目に値ゲインを与えます。

あなたの場合、SQLiteの並行性が問題になるとは思いません(少なくとも主な問題ではありません)。SQLiteでは、単一の挿入は比較的高速であり、同時実行性のパフォーマンスの問題があるため、高いワークロードで発生します。Oracleなどの他のDBMSでもおそらく同様の結果が得られます。

batchアプローチを改善するには、次のことを考慮してください。

  • journal_modeをに設定し、共有キャッシュモードWALを無効にすることを検討してください。
  • バックグラウンドスレッドを使用してキューを処理します。一定の時間間隔(1分)の代わりに、SPECIAL_FOLDER_PATHより頻繁にチェックしてください。また、キューにX Kbを超えるデータがある場合は、処理を開始します。または、キューに入れられたレコードとイベントの数を使用して、キューが処理を開始する必要があることをスレッドに通知します。
  • シングルレコードの代わりに準備されたマルチレコードを使用します。100レコードのINSERTを作成し、キューデータを単一のバッチで処理できますが、100レコードチャンクで処理できます。INSERTINSERT
  • テキスト値の代わりにバイナリフィールド値を書き込む/読み取ることを検討してください。
  • 事前に割り当てられたサイズのファイルのセットを使用することを検討してください。
于 2013-01-06T05:36:46.327 に答える
1

sqlite3_busy_timeout待機しているテーブルのロックが解除されてもすぐには戻らないため、かなり非効率的です。

各テーブルを保護するためにクリティカルセクション(TCriticalSection?)を作成してみます。行を挿入する前にクリティカルセクションに入り、その直後に終了すると、SQLiteが提供するよりも優れたテーブルロックが作成されます。

ただし、アクセスパターンを知らなければ、これが1分に相当する挿入を単一のトランザクションにバッチ処理するよりも高速であるかどうかを判断するのは困難です。

于 2013-01-06T04:37:22.613 に答える