PSQL Programmer's Guide (v11)

マルチレコードのオペレーション (トランザクショナル インターフェイス)

Pervasive PSQL は、複数のレコードまたは複数のレコードの一部にフィルタリングを行い、データを返すのに、高いパフォーマンスのメカニズムを提供します。このメカニズムは、Extended オペレーションと呼ばれ、4 つの特別なオペレーション コードでサポートされます。

これらのオペレーション のコードの記述方法については、『Btrieve API Guide』を参照してください。このセクションでは、これらのオペレーションを最高のパフォーマンスで使用するために、最適化する方法を説明します。

用語

次の語はほかの状況では別の意味を持つことがあります。このセクションでの用途では、次のような定義になります。

ディスクリプター
拡張式とも呼ばれます。Btrieve Extended オペレーションをどのように実行するかを示す、データ バッファー全体の内容です。

フィルター
拡張式の一部は選択されるレコードに適用される選択式を表します。

条件
単一の論理演算子を使用するフィルターの一部です。

コネクタ
後続の条件を接続する論理演算子です。AND、OR、または NONE のいずれかになります。

エクストラクタ
拡張式の一部で、どのデータを返すかを定義します。

キー
インデックス定義全体で、複数のセグメントを含むこともできます。Get オペレーションでは、MicroKernel がデータ ファイル内を単一のキー パスで移動することが必要です。

キー セグメント
複合インデックス、またはマルチセグメント キーとも呼ばれ、複数のセグメント定義ができます。各セグメントには、オフセット、長さ、データ型などを定義します。

背景

Extended オペレーションに対するフィルターの評価メカニズムは、非常に高速に設計されています。余計な処理を行わず直接的な方法で式を評価します。このアプローチにより、インターフェイスが独特な方法をとっていることに気付かれることでしょう。

検証

Extended オペレーションがステータス コード 62(無効なディスクリプター)を返す場合がたくさんあります。最も一般的なものを以下に挙げます。

最適化

Extended オペレーションの最適化というのは、現在のキー パスにフィルター条件を満たすレコードが残っている可能性がない場合に、MicroKernel がそのキー パスを使用してレコードを探すのをやめることができる、ということです。Pervasive PSQL 2000i SP3 以降、MicroKernel は複数の条件で最適化を行うことができます。ただし、それらの条件が順次発生し、現在のキーのセグメントに合致している場合に限ります。

各条件の評価時に、MicroKernel は指定されたセグメントが最適化可能かどうかを決定します。最適化を実行するには、以下のすべてが真である必要があります。

実際の方向はオペレーションによって示される方向だけでなく、現在のキーが降順か昇順かにも左右されます。

表 33 Extended オペレーションの実際の方向
 
昇順のキー セグメント
降順のキー セグメント
Get/Step Next
昇順/前方
降順/後方
Get/Step Prev
降順/後方
昇順/前方

以降のすべてのセグメントに対する最適化は、以下のいずれかによって無効にされます。

後述の例では次のサンプル データを使用します。

表 34 マルチレコード オペレーション用のサンプル データ
レコード
Field 1
Field 2
Field 3
Field 4
1
AAA
AAA
AAA
XXX
2
AAA
BBB
BBB
OOO
3
AAA
CCC
CCC
XXX
4
BBB
AAA
AAA
OOO
5
BBB
AAA
BBB
XXX
6
BBB
AAA
CCC
OOO
7
BBB
BBB
AAA
XXX
8
BBB
BBB
BBB
OOO
9
BBB
BBB
CCC
XXX
10
BBB
CCC
AAA
OOO
11
BBB
CCC
BBB
XXX
12
BBB
CCC
CCC
OOO
13
CCC
AAA
CCC
XXX
14
CCC
CCC
AAA
OOO

上のテーブルは、Field 1、Field 2、および Field 3 がこの順で複合キーであるとします。アプリケーションでは、このファイルに対し、前述の 3 つのフィールドから成るセグメント キーを使用して GetFirst オペレーションを実行し、引き続き GetNextExtended オペレーションを実行します。以下の例には想定されるかっこが含まれていることに注意してください。フィルターが左から右へ評価されるとき、かっこはこの位置にのみ出現します。

キー セグメントに対して最適化を行うためには、フィルター条件に指定したオフセット、長さ、データ型、大文字小文字の区別、および ACS はキー定義と同一である必要があることを忘れないでください。

(Field1 = AAA AND (Field2 = AAA AND (Field3 = AAA)))
MKDE はレコード 1 を取得し、ステータス コード 64 (最適化限度を越えた)で検索を停止します。最適化条件を満たす最後に調べたレコードはレコード 1 で、これが現在のレコードになります。Pervasive.SQL 2000 SP3 より前のエンジンでは、1 つの条件しか最適化することができなかったため、現在のレコードはレコード 3 のままでした。

(Field1 = AAA OR (Field2 = AAA OR (Field3 = AAA)))
MKDE はレコード 1、2、3、4、5、6、7、10、13 および 14 を取得し、ステータス コード 9(ファイルの終わりに達した)を返します。最初の条件に OR コネクタが含まれているため、どの条件も最適化されません。現在のレコードは、レコード 14 になります。

(Field1 = BBB AND (Field2 = BBB OR (Field3 = BBB)))
MKDE はレコード5、7、8、9 および 11 を取得し、ステータス コード 64 を返します。OR コネクタが含まれていないため、最初の条件が最適化されましたが 2 番目の条件は最適化されませんでした。最適化条件を満たす最後に調べたレコードはレコード 12 で、これが現在のレコードになります。

(Field4 = OOO AND (Field2 = BBB AND (Field3 = BBB)))
MKDE はレコード 2 と 8 を取得し、ステータス コード 9 を返します。最初のキー セグメントに対してはどの条件も最適化されず、したがって次のセグメントも最適化されません。現在のレコードは、レコード 14 になります。

(Field1 = BBB AND (first byte of Field2 = B AND (Field3 = BBB)))
MKDE はレコード 8 を取得し、ステータス コード 64 を返します。最初の 2 つの条件は最適化されますが、2 番目の条件がサブ文字列であるため、3 番目の条件は最適化されません。最適化条件を満たす最後に調べたレコードは、レコード 9 です。Pervasive.SQL 2000 SP3 より前のエンジンは 1 つの条件しか最適化できなかったため、レコード 12 が現在のレコードになります。

(Field1 = BBB AND (Field2 = Field3))
これは、2 番目のオペランドが定数ではなくレコードの別のフィールドであることを示す、+64 のバイアスを比較コードに使用して行われます。MKDE はレコード 4、8、および 12 を取得し、ステータス コード 64 を返します。最初の条件は最適化されますが、2 番目の条件は定数と比較されないため最適化されません。最適化条件を満たす最後に調べたレコードは、レコード 12 です。

(Field1<= BBB AND (Field2 <= BBB AND (Field3 <= BBB)))
MKDE はレコード 1、2、4、5、7 および 8 を取得し、ステータス コード 64 を返します。最初の条件は最適化されますが、論理演算子 OR を含まないため次の条件は最適化されません。最適化条件を満たす最後に調べたレコードは、レコード 12 です。

(Field1= BBB AND (Field2 < BBB AND (Field3 < BBB)))
MKDE はレコード 4 を取得し、ステータス コード 64 を返します。最初の条件は最適化されますが、2 番目の条件は論理演算子 EQ を含まないため最適化されません。最適化条件を満たす最後に調べたレコードは、レコード 12 です。

(Field1= BBB AND (Field2 = BBB AND (Field3 < BBB)))
MKDE はレコード 7 を取得し、ステータス コード 64 を返します。最初の 2 つの条件は EQ を使用しているため最適化されますが、3 番目の条件は最適化されません。最適化条件を満たす最後に調べたレコードは、レコード 9 です。Pervasive.SQL 2000 SP3 より前のエンジンは 1 つの条件しか最適化できなかったため、レコード 12 が現在のレコードになります。

(Field2>= AAA AND (Field2 <= BBB AND (Field1 >= AAA) AND (Field1 <= BBB))))
MKDE はレコード 1、2、4、5、6、7、8 および 9 を取得し、ステータス コード 64 を返します。最初の 3 つの条件は最初のキー セグメントに対して最適化されませんが、これらはすべて AND で結合されているため、4 番目の条件は検索を最適化するのに使用されます。2 番目の条件は、4 番目の条件の直後に発生すれば最適化することができます。しかし、キー セグメントに関連する位置がずれているため、最適化されません。1 つのキー セグメントのみが最適化されるため、最適化条件を満たす最後に調べたレコードは、レコード 12 になります。Pervasive.SQL 2000 SP3 には不具合があり、最適化可能な条件が最初に発生しない場合には最適化が妨げられます。したがって、SP3 エンジンは同じレコードを取得しますが、ステータス コード 9 を返します。

パフォーマンスのヒント

このセクションでは、オペレーションの速度を上げる方法に関して説明します。

コネクタ

Extended オペレーションは論理式を左から右へ評価するため、この機能は、最も効率的な方法で必要なデータを抽出するために式を評価するのに使用することはできません。Extended オペレーションは、最初にカーソルをファイル内の適切な位置に設定して Get または Step オペレーションと共に使用するように設計されています。したがって、最初に提案できることは次のようになります。

言い換えると、インデックスにないフィールドに対する OR で結合する条件は、インデックス付きのフィールドに対する最適化可能な条件の後に追加するのが適切です。たとえば、全国の電話帳から、テキサス州に住む "William"、"Bill"、"Billy" または "Billybob" という名前の人をすべて検索するとします。State フィールドのキーを使用し、GetEqual を使用してテキサス州の最初の人に現在のレコードを設定します。次に (State = "Texas" AND (FirstName = "William" OR (FirstName = "Bill" OR (FirstName = "Billy" OR (FirstName = "Billybob"))))) のようなフィルターを使って GetNextExtended を呼び出します。エクストラクタのリジェクト カウントが 10,000 で検索する最大レコード件数が 100 の場合、GetNextExtended はおよそ 10,000 レコードを見た後制御を戻します。しかし、テキサス州の 14,000,000 人を処理するには、ユタ州に到達してステータス コード 64(フィルター制限に達しました)が返されるまで、同じ GetNextExtended オペレーションを何度も何度も繰り返す必要があります。この処理は各レコードを 1 度に 1 つずつアプリケーションに転送するよりはずっと速く行われます。

しかし、State と FirstName に複数のインデックスが存在した場合はどうでしょうか。上の GetNextExtended は動作はしますが、4 つの州と FirstName の組み合わせのそれぞれで GetEqual および GetNextExtended を行って両方のフィールドで最適化を行えば、ずっと速く処理できます。

したがって、インデックスが使用できない場合は、OR コネクタを使ったフィルターを使用することが唯一有効な方法であることがわかります。キーに一致するフィールドに対する AND コネクタが優先されます。

リジェクト カウント

もう 1 つ理解する必要のある問題は、リジェクト カウントの設定方法です。使用するアプリケーションが MicroKernel エンジンのサービスを受ける唯一のアプリケーションである場合は、ネットワーク トラフィックまたは内部的な通信処理を最低限に保つことができるため、最大のリジェクト カウントを使用することが最も効果的です。ただし、並行処理が高い頻度で行われる環境でたくさんのアプリケーションが実行される場合は、リジェクト カウントの設定が大きすぎると重大な結果を招きます。

MicroKernel は、1 つのファイルに複数のアトミックな Btrieve オペレーションを実行中であっても、同時にたくさんの Btrieve 要求を処理することができます。したがって、読み取りスレッドがいくつでも許容されるだけでなく、1 つの書き込みスレッドが同じファイルにアクセスできます。ほとんどの Btrieve オペレーションは読み取り操作で、それらは実行に多くの時間を要しません。そのため、書き込み操作を行う場合は、すべての読み取り処理が終わるのを待ってから、レコードの挿入、更新、または削除を行う瞬間にファイルをロックします。この調整は、完了するのに長い時間がかかる読み取り操作を行わない限り、非常によく機能します。リジェクト カウントの値を大きく設定した Extended オペレーションで、レコードが見つからない場合にそうなります。これは読み取り処理を何度も何度も繰り返します。ほかの読み取り操作は問題なく完了しますが、書き込み操作は停滞し始めます。書き込み操作がファイルに対して 100 回書き込みアクセスを試行すると、フラストレーション カウントと呼ばれる回数に達します。この時点で、書き込み操作はすべての新しい読み取りスレッドにブロックをかけます。その結果、このファイルに対するすべての Btrieve オペレーションは Extended オペレーションが完了するまで停止します。

100 から 1000 のリジェクト カウントを使用したとしても、レコードをアプリケーションに戻してから拒否するよりも、MicroKernel に読み取りと拒否を実行させる方がよいです。


レコードの挿入と更新 (トランザクショナル インターフェイス)

キーの追加と削除 (トランザクショナル インターフェイス)