私は現在、SQLiteデータベースに依存するいくつかの機能を実装しています。そうしている間、私は私が予期していなかった制限に直面しています。自分の問題に正しい方法で取り組んでいるのだろうかと思いました。要件を考慮した別のアプローチを誰かが提案できることを願っています。
ゴール
目標は、オブジェクトの大規模なコレクションを可能な限り高速にデータベースに格納することです。ただし、いずれかの時点でこれらのオブジェクトの保存を行わないことが決定された場合、その操作はデータベースに影響を与えないはずです。正確なストレージクエリ(「挿入」)は、以前の挿入に依存します。
使用事例
「インスタンス情報パッケージ」の非常に大きなコレクションを考えてみましょう。各パッケージは、対応する抽象インスタンスの知識の一部を表しています。したがって、コレクション全体は、1つ以上の抽象的なインスタンスの完全な知識を表します。各パッケージの情報は次のもので構成されています。
- instance_id; この情報が関連する抽象インスタンスを一意に識別するために使用されます。
- 属性マップ。(attribute_uri、attribute_value)-attribute_uriが属性を一意に識別し、attribute_valueが対応するテキスト値であるペア。
instance_idとattribute_idはどちらも、それぞれTBL_INSTANCESとTBL_ATTRIBUTESのテーブルにあります。ここで使用するデータベースモデルはEAVモデルです。
挿入後、テーブルTBL_ENTRIESには次の形式のエントリが含まれている必要があります。
[ entry_id | instance_id | attribute_id | attribute_value ]
問題
実装は簡単なようでした:
- セーブポイントを設定する
- トランザクションを開始します
- TBL_ENTRIESの多くの挿入のステートメントを準備します
- コレクション内のインスタンスごとに:
- 4.1。TBL_INSTANCESでinstance_idを検索します。存在しない場合は、TBL_INSTANCESに追加します
- 4.2。インスタンスの属性マップの各属性について:
- 4.2.1。TBL_ATTRIBUTESでattribute_idを検索します。存在しない場合は、TBL_ATTRIBUTESに追加します。
- 4.2.2。TBL_ENTRIESにエントリを追加します
- いずれかの時点でエラーが発生した場合は、セーブポイントにロールバックします。それ以外の場合はコミットします。
残念ながら、ルックアップ手順(4.1および4.2.1)で、SQLiteは「トランザクション内でトランザクションを開始できません」というエラーを報告します。ドキュメントを読むと、ルックアップがsqlite3_execルーチンを呼び出すという事実にあるようです。これは(私が間違っていない限り)内部でトランザクションをセットアップしているようです。
質問
ネストされたトランザクションが許可されていない場合、ルックアップ手順(基本的には「INSERTORREPLACE」式の後に「SELECT」クエリが続く)をどのように実行する必要がありますか?それらを回避する方法、または現在のトランザクション内でsqlite3_execを使用する方法はありますか?そうでない場合、私は自分の問題に間違った方法でアプローチしていますか?おそらく、キーとして個別の整数を使用するべきではありません。たとえば、対応するattribute_idを検索する代わりに、attribute_uriをキーとして直接使用する必要があります。
いずれにせよ、実際の速度の向上は、属性のコレクションではなく、インスタンスのコレクションに対するステートメントの準備にあるため、トランザクション中に同等のことを行う必要があります。インスタンスには1つまたは2つの属性しかありませんが、インスタンスの数はインスタンスコレクションでは、常に非常に大きくなります。
私はC/C ++、SQLite3.7を使用しています。
私のアプローチに関する提案や意見は大歓迎です!