39

私は、データベースと特に SQLite に関するさまざまなベスト プラクティスを読むことに時間を費やしてきました。読んでいるうちに、やってはいけないことをたくさんしていることがわかりました。これらの問題を修正しようとしたときに、ADO 実装で SQLite を使用することの詳細について考えると混乱しました。

私の混乱は、特に準備されたステートメントと接続プーリングに起因しています。

http://msdn.microsoft.com/en-us/library/ms971481.aspxを読んでいるときに、接続はトランザクションに対してのみ開く必要があることがわかりました。トランザクションが完了したら、接続を閉じる必要があります。なぜそうなのかははっきりとはわかりませんが、著者は私よりもよく知っているという仮定に基づいて作業を進めてきました。閉鎖されました。それは単にプールに戻されたことを意味します。

クエリと挿入を改善するために、準備済みステートメントの使用について読みました。SQLite では、準備されたステートメントは本当にパフォーマンスを向上させますか? http://petesbloggerama.blogspot.com/2007/02/sqlite-adonet-prepared-statements.htmlの両方が、複数回実行されるクエリを実行するときに、準備されたステートメントが進むべき道であることを示しているようです。また、準備済みステートメントは接続に固有のものであり、接続が閉じられると準備済みステートメントが失われることも読みました。

私の混乱はこれです。接続を開いたり閉じたりしている場合 (これは、スレッド プールが原因で接続が閉じられていることを意味する場合とそうでない場合があります)、準備されたステートメントから実際にどれだけの使用が得られますか? 1000 個のオブジェクトがある場合、単一のトランザクションで保存する必要がある場合、準備済みステートメントが大いに役立つことは理解できます。ただし、接続を閉じると、最初のオブジェクトから生成された準備済みステートメントが失われるため、トランザクションに単一のオブジェクトを保存することでメリットが得られるとは思いません。これは本当の声明ですか?

私の混乱は、準備されたステートメントが私の SQLiteCommand オブジェクトのスコープにリンクされていると信じているという事実によって助長されています。

頻繁に実行するクエリを表す SQLiteCommand を作成する場合、準備されたステートメントがアクティブな状態を維持するために、その SQLiteCommand をメモリに保持する必要がありますか?

同じ SQLite ステートメントで新しい SQLiteCommand を作成した場合、新しい SQLiteCommand は以前のものと同じであり、使用できる準備済みステートメントがあると認識されますか?

SQLiteCommand をメモリに保持し、さまざまなトランザクションの接続を開いたり閉じたりするときにそのパラメーターと接続を変更すると、基本的に、異なる接続間で準備済みステートメントを維持できますか?

この時点で考えすぎている可能性が高いですが、これらの相互作用をよりよく理解して、それらを最大限に活用できるようにしてください.

4

2 に答える 2

18

接続プーリングと準備された (コンパイルされた) ステートメントはどちらも、制限のある単なるツールであり、考えられるすべての状況に同等に適しているアプローチはないことを覚えておくと役立ちます。これを念頭に置いて、接続プーリングと準備済みステートメントをいつ使用するかを思い出してください。

接続プールを使用する考えられる理由

接続プーリングは、接続が高価な場合に役立ちます。次に例を示します。

  • 接続 (SQL Server または Oracle DB へのネットワーク接続) を確立するにはかなりの時間がかかります。システム パフォーマンスを向上させるために、開いている接続を「キャッシュ」することは有益です。
  • 接続は制限され、アプリケーション内 (複数の同時要求を処理する Web アプリケーションからの接続) またはアプリケーション間で共有されるため、他のクライアントが続行できるように、できるだけ早く解放する必要があります。

プリペアド ステートメントを使用する考えられる理由

プリペアド ステートメントは、解析時間を短縮することで、再利用可能なクエリのパフォーマンスを向上させることを目的としています。

SQLite: 最良の選択は何ですか?

答えは、アプリケーションの要件によって異なります。個人的には、SQLite 接続プールが必ずしも適切な選択であるかどうかはわかりません。アプリケーションがシングル スレッドの場合は、SQLite DB への単一の永続的な接続を使用するのが最適な場合があります。これは、プールよりもはるかに高速であり、準備済みステートメントも使用できる可能性があります。これは、接続プールが非常に合理的なデフォルトである SQL Server とは異なります。

パフォーマンスが重要な場合は、アプリケーションをプロファイリングして、SQLite 接続プールがシナリオに役立つかどうかを確認する必要があります。

具体的な質問

回答のほとんどは、現在のSystem.Data.SQLiteプロバイダーソースに関連しています。

接続を開いたり閉じたりしている場合 (スレッドプールが原因で接続が閉じられていることを意味する場合とそうでない場合があります)、準備されたステートメントから実際にどれだけの使用が得られますか?

一般に、プールから出てくる接続は新しいものとして扱う必要があります。つまり、以前に準備されたステートメントから利益を得ることは期待できません。コマンドと接続の両方を維持しない限り、ステートメントは「再準備」されます。

ただし、接続を閉じると、最初のオブジェクトから生成された準備済みステートメントが失われるため、トランザクションに単一のオブジェクトを保存することでメリットが得られるとは思いません。これは本当の声明ですか?

これは真実です。

頻繁に実行するクエリを表す SQLiteCommand を作成する場合、準備されたステートメントがアクティブな状態を維持するために、その SQLiteCommand をメモリに保持する必要がありますか?

はい、保管する必要があります。SQLiteCommand準備されたステートメントへの参照を保持します。

同じ SQLite ステートメントで新しい SQLiteCommand を作成した場合、新しい SQLiteCommand は以前のものと同じであり、使用できる準備済みステートメントがあると認識されますか?

サポートされていないと思います。

SQLiteCommand をメモリに保持し、さまざまなトランザクションの接続を開いたり閉じたりするときにそのパラメーターと接続を変更すると、基本的に、異なる接続間で準備済みステートメントを維持できますか?

の接続を変更するSQLiteCommandと、ステートメントは「再作成」されます。

于 2012-11-22T02:30:18.290 に答える
1

核心的な問題が何であるかを正確に把握できませんでしたが、問題が 1 つのトランザクションに非常に短い時間で一括挿入ステートメントを挿入する方法である場合。

以前に見つけたヘルパー クラスを次に示します。

SQLiteBulkInsertHelper.cs

次のように使用できます。

SQLiteBulkInsertHelper ContactBlk = new SQLiteBulkInsertHelper("<SQLiteConnection>","<Table Name>");
ContactBlk.AllowBulkInsert = true;
ContactBlk.AddParameter("<Column Name>", /*Column Data Type*/System.Data.DbType.Int64);
ContactBlk.AddParameter("<Column Name>", /*Column Data Type*/System.Data.DbType.String);
ContactBlk.Insert(new object[] {<First Column Value>,<Second Column Value>});
ContactBlk.Flush();

問題の解決策と思われる場合は、試してみてください。

于 2012-06-18T13:36:29.523 に答える