DeepSee クエリ・エンジンの仕組み
この付録では、DeepSee でクエリをどのように実行しているかについて説明します。この情報は、クエリ・プランを表示する場合や問題を診断する場合に役立ちます。この付録では、以下の項目について説明します。
この付録では、DeepSee によって内部的に使用されるグローバルに関する情報を提供します。この情報はデモンストレーションを目的としたものであり、これらのグローバルを直接使用することはできません。これらのグローバルの編成は、予告なしに変更される場合があります。
概要
このセクションでは、基本概念について説明します。詳細は、次のセクションを参照してください。
ビットマップ・インデックスの使用
キューブ・クラスのコンパイル時に、DeepSee クエリ・エンジンが使用するファクト・テーブル・クラスが作成されます。このクラスは、このエンジンが必要とするすべてのビットマップ・インデックスを定義します。これらのビットマップ・インデックスは、^DeepSee.Index グローバルに格納されます。キューブのビルド時または同期時に、必要に応じてこれらのインデックスが更新されます。ファクト・テーブルでレコードを検索する必要がある場合、このクエリ・エンジンは必要に応じてこれらのビットマップ・インデックスを組み合わせて使用します。
例えば、1 つのビットマップ・インデックスが、Product Category レベルの Snack メンバに関係するすべてのレコードへのアクセスを提供するとします。もう 1 つのビットマップ・インデックスが、City レベルの Madrid メンバに関係するすべてのレコードへのアクセスを提供するとします。さらにもう 1 つのビットマップ・インデックスが、YearSold レベルの 2012 メンバに関係するすべてのレコードへのアクセスを提供するとします。Snack、Madrid、および 2012 に関係するすべてのレコードを探し出すために、DeepSee はこれらのビットマップ・インデックスを組み合わせて、得られたインデックスを使用してレコードを取得します。
キャッシュ処理
(既定で) 512,000 レコードより多く使用するキューブの場合、DeepSee は、結果キャッシュを保持し、使用します。この場合、DeepSee は、クエリを実行するたびに結果キャッシュを更新し、後で可能な限りこの結果キャッシュを使用します。結果キャッシュには以下のグローバルが含まれています。
-
^DeepSee.Cache.Results には、指定のキューブに対して以前に実行された各クエリの値が格納されます。このグローバルには、これらのクエリに関するメタ情報も格納されます。このメタ情報を使用してクエリを迅速に再実行できます。クエリの情報を取得するために、DeepSee はキューブ名とクエリ・キー (正規化されたクエリ・テキストのハッシュ) を使用します。
指定されたキューブ名およびクエリ・キーについて、このグローバルには最終値と中間値が格納されたサブノードのセットが含まれています。これらのサブノードは、バケット番号別に分類され、さらに結果セル別に分類されています (バケットは、ソース・テーブル内の連続するレコードのセットです。次のサブセクションを参照してください)。
以下に例を示します。
^DeepSee.Cache.Results("HOLEFOODS","en2475861404","data",-1,2,3)=67693.46 ^DeepSee.Cache.Results("HOLEFOODS","en2475861404","data",-1,2,4)=425998.02 ^DeepSee.Cache.Results("HOLEFOODS","en2475861404","data",-1,2,5)=212148.68 ^DeepSee.Cache.Results("HOLEFOODS","en2475861404","data",0,2,3)=301083.77 ^DeepSee.Cache.Results("HOLEFOODS","en2475861404","data",0,2,4)=1815190.08 ^DeepSee.Cache.Results("HOLEFOODS","en2475861404","data",0,2,5)=910314.95 ^DeepSee.Cache.Results("HOLEFOODS","en2475861404","data",1,2,3)=78219.74 ^DeepSee.Cache.Results("HOLEFOODS","en2475861404","data",1,2,4)=463165.12 ^DeepSee.Cache.Results("HOLEFOODS","en2475861404","data",1,2,5)=233031.39 ^DeepSee.Cache.Results("HOLEFOODS","en2475861404","data",2,2,3)=79153.44 ^DeepSee.Cache.Results("HOLEFOODS","en2475861404","data",2,2,4)=461472.97 ^DeepSee.Cache.Results("HOLEFOODS","en2475861404","data",2,2,5)=233584.42 ^DeepSee.Cache.Results("HOLEFOODS","en2475861404","data",3,2,3)=76017.13 ^DeepSee.Cache.Results("HOLEFOODS","en2475861404","data",3,2,4)=464553.97 ^DeepSee.Cache.Results("HOLEFOODS","en2475861404","data",3,2,5)=231550.46
この例では、"data" に続く最初の添え字はバケット番号を示しています。バケット -1 および 0 は特殊なバケットです。-1 バケットはアクティブ・バケット (最新のレコードを表します) で、0 バケットはすべてのバケットにわたる統合結果です。
最後の 2 つの添え字は、結果セルをその位置で示しています。このノードの値は、指定された結果セルの値です。
例えば、^DeepSee.Cache.Results("HOLEFOODS","en2475861404","data",0,2,3) には、すべてのバケットにわたるセル (2,3) の統合値が格納されています。この数値は、他のノードに格納されているこのセルの中間値の合計です。
-
^DeepSee.Cache.Axis (以前に実行されたクエリの軸に関するメタデータが格納されています)。DeepSee は、指定されたクエリの軸を繰り返し処理する必要が生じるたびにこの情報を使用します。キャッシュしたデータは格納されません。
-
^DeepSee.Cache.Cells (以前に実行したクエリで返されたセルのキャッシュされたメジャー値が格納されています)。セルは、メジャーではない任意の数のメンバが交差する位置にある共通部分です (Madrid、Snack、および 2012 の共通部分など)。このグローバルでは、各セルはセル仕様で表されます。セル仕様は、専用のコンパクトな内部使用の式です。以下は、部分的な例です。
^DeepSee.Cache.Cells("HOLEFOODS",1,":::2012:::::1:1::1:1",1)=$lb(1460.05) ^DeepSee.Cache.Cells("HOLEFOODS",1,":::2012:::::1:1::1:2",1)=$lb(606.22) ^DeepSee.Cache.Cells("HOLEFOODS",1,":::2012:::::1:1::1:3",1)=$lb(40.17) ^DeepSee.Cache.Cells("HOLEFOODS",1,":::2012:::::1:1::1:4",1)=$lb(63.72) ^DeepSee.Cache.Cells("HOLEFOODS",1,":::2012:::::1:1::2:1",1)=$lb(3778) ^DeepSee.Cache.Cells("HOLEFOODS",1,":::2012:::::1:1::2:2",1)=$lb(1406.08) ^DeepSee.Cache.Cells("HOLEFOODS",1,":::2012:::::1:1::2:3",1)=$lb(117.31) ^DeepSee.Cache.Cells("HOLEFOODS",1,":::2012:::::1:1::2:4",1)=$lb(412.24)
最初の添え字はキューブ名、2 番目の添え字はバケット番号、3 番目の添え字はセル仕様 (例えば ":::2012:::::1:1::1:1") です。最後の添え字はメジャーを示しています。指定されたノードの値は、指定されたキューブ、セル、およびバケットで指定されたメジャーの集約値です。この場合、内部処理の都合上、結果は $LISTBUILD 形式で表現されます。このグローバルはクエリ・キーを使用しません。これは、複数のまったく異なるクエリによって同じセルが簡単に生成されるためです。
このグローバルは、セル・キャッシュと呼ばれ、キャッシュでバケットを使用する場合にのみ生成されます。
セル・キャッシュには、アクティブ・バケットの値は含まれていません。また、(すべてのバケットにわたって統合された) 0 バケットの値も含まれていません。
ユーザがクエリを実行しない限り、これらのグローバルには値が生成されません。クエリの繰り返し実行に伴って、キャッシュの内容は充実していきます。その結果、クエリを再実行する代わりにキャッシュを使用できるようになるので、パフォーマンスが向上します。
キャッシュには、isReference="true" と定義されているプロパティの値は含まれていません。これらの値は常に、実行時に取得されます。
バケット
(既定で) 512,000 レコードより多く使用するキューブの場合、DeepSee は、キャッシュをバケットにまとめます。各バケットは、以下の図のように、ファクト・テーブル内で連続する大量のレコードに対応しています。
最後のバケット (部分的なバケット) はアクティブなバケットであり、セル・キャッシュには示されません。
既定で、ファクト・テーブルには、ソース・テーブルと同じ順序でレコードが格納されます。キューブの [初期ビルド順] オプションを指定して、キューブの完全なビルドを実行するときに DeepSee がソース・テーブルのレコードを検証する順序を制御できます。"DeepSee モデルの定義" の “他のキューブ・オプション” を参照してください。
ファクト・テーブルが更新されるたびに、DeepSee は必要に応じてキャッシュの一部を破棄します。より具体的に言うと、ファクト・テーブルにあるバケットのうち、影響を受ける部分のレコードを使用するバケットが無効になります。その他のバケットはそのままです。クエリの実行時には、有効なバケットに対してのみキャッシュされたデータが使用されます。キャッシュされた有効な結果が存在しないレコードの場合、DeepSee はビットマップ・インデックスを使用して必要な中間値を再計算します。クエリ実行の最後のフェーズとして、DeepSee は結果を統合します。したがって、DeepSee は、キャッシュされたデータと新規データまたは変更されたデータとの組み合わせから得られた結果を提供できます。また、エンジン動作の中にはバケット単位で分割できるものがあるので、DeepSee は一部の処理を並行して実行できます。
既定のバケット・サイズ
既定では、バケットは 512,000 個のレコードです。バケット・サイズは、bucketSize オプションによって制御されます。このオプションでは、バケット・サイズはレコードのグループの数を表す整数値で示されます。グループは、64,000 個の連続するレコードで構成されています。既定の bucketSize は 8 です。このため、既定のバケットは、8 x 64,000 レコード、つまり 512,000 レコードです。bucketSize の詳細は、"DeepSee モデルの定義" の “<cube>” を参照してください。
エンジン・ステップ
クエリを処理するために、DeepSee は以下のステップを実行します。
-
準備 (プロセス内で実行されます。つまりこのステップはバックグラウンド・プロセスとしては起動しません)。このフェーズで実行される手順は以下のとおりです。
-
DeepSee がクエリを解析して、それをオブジェクト表現 (解析ツリー) に変換します。
この解析ツリーでは、クエリの各軸が独立して表現されます。1 つの軸がクエリの全般的なフィルタを表します。
-
DeepSee が、解析ツリーを正規化したクエリ・テキストに変換します。
この正規化したクエリ・テキストでは、例えば、すべての %FILTER 節が、同等な 1 つの WHERE 節にまとめられています。
-
DeepSee が、正規化したクエリ・テキストに基づいてハッシュを生成します。DeepSee は、このハッシュ値をクエリ・キーとして使用します。クエリ・キーを使用すると、この付録で説明したグローバルの中でこのクエリの結果を検索できます。
-
^DeepSee.Cache.Results にある以前に実行したクエリ結果の中に再利用できるものがある場合、DeepSee はその結果を再利用し、以降のステップを省略します。
-
-
軸の実行 (これもプロセス内で実行されます)。このフェーズで実行される手順は以下のとおりです。
-
DeepSee がサブクエリを実行します。
-
DeepSee がスライサ軸 (WHERE 節) を検証し、関連フィルタ処理 (例えば、サブジェクト領域のフィルタ) でマージして、^DeepSee.Cache.Axis をこの軸に関する情報で更新します。
-
残りの各軸も検証して、^DeepSee.Cache.Axis を更新します。
-
-
セルの実行 (複数の並行処理によって、バックグラウンドで実行します)。このフェーズで、DeepSee は、以下のようにバケットごとに結果の各セルの中間値を取得します。
-
最初に、指定されたバケットのセルの値が ^DeepSee.Cache.Cell に格納されているかどうかを確認します。
格納されている場合、DeepSee はその値を使用します。
-
格納されていない場合、^DeepSee.Index の該当ノードを使用して、必要なビットマップ・インデックスを取得します。これらのビットマップ・インデックスを組み合わせて得られたインデックスを使用して、ソース・テーブルの中で該当するレコードを検索します。
キャッシュがバケットを使用している場合、DeepSee は今後のクエリで使用するために ^DeepSee.Cache.Cell にノードを追加します。
-
-
統合 (プロセス内で実行されます)。このフェーズで実行される手順は以下のとおりです。
-
スライサ軸ごとに、DeepSee がその軸の結果セルをそれぞれ検証します。
結果セルごとに、^DeepSee.Cache.Cell の中でそのセルの値が格納されているすべてのノードを検索します。
次に、それらの値を結合します。
-
結果セルごとにスライサ軸全体にわたって結果を結合し、単一の値を取得します。
詳細は、次のセクションを参照してください。
DeepSee は、統合フェーズ中に CURRENTMEMBER 関数を評価します。その他の関数については、この処理のより早い段階で評価します。
-
軸のたたみ込み
統合フェーズでの DeopSee は、複数のスライサ軸が存在すると、結果セルごとにそれらの軸全体にわたる結果を統合します。このステップを、軸のたたみ込みといいます。
軸のたたみ込みを実行すると、どのスライサ軸にも NULL の結果がないソース・レコードは複数回カウントされます。
軸のたたみ込みが必要かどうかを判断するために、DeepSee は、すべてのソース (サブジェクト領域、ピボット・テーブル、およびダッシュボード) から、クエリに適用したすべてのフィルタを検討します。以下のように、これらのフィルタの最終的な組み合わせから、軸のたたみ込みが必要かどうかが決まります。軸のたたみ込みが必要になる状況を以下のテーブルに示します。
フィルタの形式 | 軸のたたみ込みの実行 |
---|---|
単一のメンバ。例 : [PRODUCT].[P1].[PRODUCT CATEGORY].&[Candy] | なし |
単一のメジャー。例 : [MEASURES].[Units Sold] | なし |
タプル (複数のメンバの組み合わせ、または複数のメンバと 1 つのメジャーの組み合わせ)。例 : ([Outlet].[H1].[City].&[7],[PRODUCT].[P1].[PRODUCT CATEGORY].&[Candy]) | なし |
%TIMERANGE 機能 CROSSJOIN(%TIMERANGE([BirthD].[H1].[Date].&[10000],[BirthD].[H1].[Date].&[50000]),%TIMERANGE([BirthD].[H1].[Date].&[40000],[BirthD].[H1].[Date].&[NOW])) でラップされたメンバを使用する交差結合 | 可 |
その他の交差結合。例 : NONEMPTYCROSSJOIN([Outlet].[H1].[City].&[7],[PRODUCT].[P1].[PRODUCT CATEGORY].&[Candy]) | なし |
%OR 関数。複数のメンバをリストするセット式のラッパです。例 : %OR({[Product].[P1].[Product Category].&[Candy],[Product].[P1].[Product Category].&[Snack]}) | なし |
複数のメンバをリストするが、%OR は使用しないセット式。例 : {[Product].[P1].[Product Category].&[Candy],[Channel].[H1].[Channel Name].&[2]} | あり |
アナライザでこれらの式をフィルタとして作成するには、[フィルタ] ボックスに項目をドラッグ・アンド・ドロップする方法が一般的です。最後の 2 つの行にセット式を作成するには、高度なフィルタ・エディタを使用する必要があります。DeepSee は、可能な場合、自動的に %OR 関数を使用します。高度なフィルタ・エディタでは、これはオプションとしては表示されません。
クエリ・プラン
クエリツールでクエリを実行する場合はクエリ・プランを表示できます。同様に、(このドキュメントで前述したように) プログラムによってクエリを実行する場合は、結果セットの %ShowPlan() メソッドを呼び出すことができます。以下はその例です。
SAMPLES>do rs1.%ShowPlan()
-------------- Query Plan ---------------------
**SELECT {[MEASURES].[AVG TEST SCORE],[MEASURES].[%COUNT]} ON 0,[AGED].[AGE
BUCKET].MEMBERS ON 1,[GEND].[GENDER].MEMBERS ON 2 FROM [PATIENTS]****
DIMENSION QUERY (%GetMembers): SELECT %ID,DxAgeBucket MKEY, DxAgeBucket
FROM DeepSee_Model_PatientsCube.DxAgeBucket ORDER BY DxAgeBucket**
**DIMENSION QUERY (%GetMembers): SELECT %ID,DxGender MKEY, DxGender
FROM DeepSee_Model_PatientsCube.DxGender ORDER BY DxGender**
**EXECUTE: 1x1 task(s) **
**CONSOLIDATE**
-------------- End of Plan -----------------
ここでは、ドキュメントを PDF バージョンに適した形式にするために、改行とスペースが追加されています。
クエリ統計
このドキュメントで前述したように、プログラムによってクエリを実行する場合は、結果セットの %PrintStatistics() メソッドを呼び出すことができます。以下はその例です。
SAMPLES>do rs1.%PrintStatistics()
Query Statistics:
Results Cache: 0
Query Tasks: 1
Computations: 15
Cache Hits: 0
Cells: 10
Slices: 0
Expressions: 0
Prepare: 0.874 ms
Execute Axes: 145.762 ms
Columns: 0.385 ms
Rows: 144.768 ms
Members: 134.157 ms
Execute Cells: 6.600 ms
Consolidate: 1.625 ms
Total Time: 154.861 ms
ResultSet Statistics:
Cells: 0
Parse: 3.652 ms
Display: 0.000 ms
Total Time: 3.652 ms
ここに表示された値の説明を以下に示します。
-
Query Statistics — この統計のグループでは、結果セットを返したクエリに関する情報が得られます。その結果セットを使用するために実行された内容についての情報は含まれません。
-
Results Cache は、結果キャッシュが使用された場合に 1 になります。それ以外の場合は 0 になります。
-
Query Tasks は、このクエリがいくつのタスクに分割されたかのカウントです。
-
Computations は、中間計算 (集約オプションに従ってメジャーを集約するなど) を実行するために費やした時間を示します。これには、MDX 式の評価は含まれません。
-
Cache Hits は、中間キャッシュが何回使用されたかのカウントです。
-
Cells は、結果セットのすべてのセルと、計算された中間セルのカウントです。
-
Slices は、クエリ内のキューブ・スライス数のカウントです。このカウントは、WHERE 節での項目数を示します。
-
Expressions は、MDX の評価に費やした時間を示します。
キャッシュが使用された場合は、Computations、Cache Hits、Cells、および Expressions のすべてがゼロになります。
-
Prepare、Execute Axes、Execute Cells、および Consolidate は、クエリ処理の各部分に費やされた時間を示します。これらの部分は、順序どおりにリストされます。
-
Total Time は、上記の部分の合計です。
キャッシュが使用された場合は、Execute Cells と Consolidate の両方がゼロになります。これは、それらの処理部分が実行されないためです。
-
-
ResultSet Statistics — この統計グループでは、結果セットで返された後で、結果セットを使用するために実行された内容に関する情報が得られます。この値は以下のとおりです。
-
Cells は、結果セット内のセル数のカウントです。
-
Parse は、結果セットの解析に費やした時間を示します。
-
Display は、表示に費やした時間を示します。
-
Total Time は、これらの時間の合計です。
-