web-dev-qa-db-ja.com

SQLite / C#接続プーリングとプリペアドステートメントの混乱

データベース、特にSQLiteのさまざまなベストプラクティスを読んでいます。読んでいると、やるべきではないことがたくさんあるのに気づき、これらの問題を修正しようとすると、SQLiteをADO実装で使用することについて、いくつかの細かいことを考えると混乱しました。

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

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

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

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

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

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

同じSQLiteステートメントを使用して新しいSQLiteCommandを作成すると、新しいSQLiteCommandは以前のSQLiteCommandと同じであると認識され、使用できる準備されたステートメントを持っていますか?

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

私は現時点で考えている可能性が高いですが、これらのものがどのように相互作用するかをよりよく理解して、それらから最大の利益を得ることができるように願っています。

33
Lux782

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

接続プーリングを使用する可能性のある理由

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

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

準備済みステートメントを使用する可能性のある理由

準備済みステートメントは、解析時間を短縮することにより、再利用可能なクエリのパフォーマンスを向上させることを目的としています。

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

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

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

特定の質問

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

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

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

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

これは本当の声明です。

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

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

同じSQLiteステートメントを使用して新しいSQLiteCommandを作成すると、新しいSQLiteCommandは以前のSQLiteCommandと同じであると認識され、使用できる準備されたステートメントを持っていますか?

サポートされているとは思いません。

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

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

15
Serge Belov

中心的な問題は正確には把握できませんでしたが、問題が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();

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

0
Mohamed Arabi