問合せ実行計画
問合せ実行計画は、Oracle NoSQL Databaseが問合せを実行するために行う一連の操作です。
問合せ計画の概要
問合せ実行計画は、内部的には計画イテレータのツリーとして構造化されます。
各種のイテレータは、問合せに出現する様々な種類の式を評価します。通常、索引の選択および関連する索引条件の種類は、問合せのパフォーマンスに大きく影響する可能性があります。そのため開発者は、多くの場合、問合せで使用される索引と、問合せにプッシュ・ダウンされた条件を確認する必要があります。この情報を基に、索引ヒントを介して別の索引の使用を強制する場合があります。この情報は、問合せ実行計画に含まれます。すべてのOracle NoSQLドライバに、問合せの実行計画を表示するAPIが用意されています。IntelliJ、VSCode、Eclipseプラグインを含むすべてのOracle NoSQLグラフィカルUIと、Oracle Cloud Infrastructureコンソールには、問合せ実行計画を表示するためのコントロールが含まれています。
問合せで使用される最も一般的で重要なイテレータの一部を次に示します。
TABLEイテレータ
- 問合せで使用される索引のスキャン(主索引の場合もあります)。
- 索引にプッシュされるフィルタリング条件の適用
- 必要に応じて、条件を満たす索引エントリが指す行を取得します。カバー索引の場合、TABLEイテレータの結果セットは索引エントリのセットであり、それ以外の場合は表の行のセットです。
ノート:
索引は、その索引のエントリのみを使用して問合せを評価できる場合、つまり、関連付けられた行を取得する必要がない場合、問合せに関するカバー索引と呼ばれます。- target table: 問合せのターゲット表の名前。
- index used: 問合せで使用される索引の名前。主索引が使用された場合、このプロパティの値として"primary index"が示されます。
- covering index: カバー索引かどうか。
- row variable: TABLEイテレータによって生成された表の行全体にわたる変数の名前。カバー索引の場合、表の行は生成されず、この変数は使用されません。
- index scans: 実行する索引スキャンを定義する開始条件と停止条件が含まれます。
- index row variable: TABLEイテレータによって生成された索引エントリ全体にわたる変数の名前。新しい索引エントリが索引スキャンによって生成されるたびに、索引変数がそのエントリにバインドされます。
- index filtering predicate: 索引スキャンによって生成されるすべての索引エントリで評価される条件。この評価の結果がtrueの場合、索引変数はこのエントリにバインドされ、TABLEイテレータに対するnext()コールの結果として、エントリまたは関連する表の行が返されます。それ以外の場合、エントリはスキップされ、索引スキャンからの次のエントリが生成されます。このエントリで条件が再度評価され、条件を満たすエントリが見つかるまで続行されます。
SELECTイテレータ
SELECT式を実行します。
RECEIVEイテレータ
- RECEIVEイテレータ自体と、イテレータ・ツリー内でその上にあるすべてのイテレータがドライバで実行されます。
- RECEIVEイテレータの下にあるすべてのイテレータは、レプリケーション・ノード(RN)で実行されます。これらのイテレータは、RECEIVEイテレータの一意の子をルートとするサブツリーを形成します。
通常、RECEIVEイテレータは問合せコーディネータとして機能します。実行のためにサブプランを適切なRNに送信し、結果を収集します。ソートや重複削除などの追加操作を実行し、その結果をその祖先イテレータ(存在する場合)に伝播して、さらに処理できます。
分散の種類
distribution kindは、Oracle NoSQLデータベース(ストア)に参加しているRN間で問合せを分散して実行する方法を指定します。distribution kindは、RECEIVEイテレータのプロパティです。
- SINGLE_PARTITION: SINGLE_PARTITION問合せでは、WHERE句に完全なシャード・キーを指定します。その結果、結果セット全体が単一のパーティションに含まれ、RECEIVEイテレータはそのパーティションを格納する単一のRNにサブプランを送信します。SINGLE_PARTITION問合せでは、主キー索引または2次索引のいずれかを使用できます。
- ALL_PARTITIONS: 問合せでは、ここで主キー索引を使用し、完全なシャード・キーは指定しません。その結果、ストアにM個のパーティションがある場合、RECEIVEイテレータはそのサブプランのコピーをM個送信して、それぞれがM個のパーティションのいずれかで実行されるようにします。
- ALL_SHARDS: 問合せでは、ここで2次索引を使用し、完全なシャード・キーは指定しません。その結果、ストアにN個のシャードがある場合、RECEIVEイテレータはそのサブプランのコピーをN個送信して、それぞれがN個のシャードのいずれかで実行されるようにします。
問合せ実行計画を確認するための表へのデータ移入:
例のとおりに操作する場合は、スクリプトbaggageschema_loaddata.sqlをダウンロードして、次に示すように実行します。このスクリプトにより、例で使用する表が作成され、表にデータがロードされます。
java -jar lib/kvstore.jar kvlite -secure-config disable
java -jar lib/sql.jar -helper-hosts localhost:5000 -store kvstore
load
コマンドを使用して、スクリプトを実行します。load -file baggageschema_loaddata.sql
索引の作成:
baggageInfo
表に次の索引を作成します。
- 乗客予約コードに対する索引を作成します。
CREATE INDEX fixedschema_conf ON baggageInfo confNo)
- 乗客のフルネームと電話番号に対する索引を作成します
CREATE INDEX compindex_namephone ON baggageInfo (fullName,contactPhone)
- 手荷物が最後に確認された日時、最後に確認されたステーションおよび到着日時という3つのフィールドに対する索引を作成します。
CREATE INDEX simpleindex_arrival ON baggageInfo(bagInfo[].lastSeenTimeGmt as ANYATOMIC, bagInfo[].bagArrivalDate as ANYATOMIC, bagInfo[].lastSeenTimeStation as ANYATOMIC)
問合せ1: 索引レンジ・スキャンでの主キー索引の使用
SELECT fullname, ticketNo,
bag.bagInfo[].tagNum,bag.bagInfo[].routing
FROM BaggageInfo bag WHERE
1762340000000 < ticketNo AND ticketNo < 1762352000000
{
"iterator kind" : "RECEIVE",
"distribution kind" : "ALL_PARTITIONS",
"input iterator" :
{
"iterator kind" : "SELECT",
"FROM" :
{
"iterator kind" : "TABLE",
"target table" : "BaggageInfo",
"row variable" : "$$bag",
"index used" : "primary index",
"covering index" : false,
"index scans" : [
{
"equality conditions" : {},
"range conditions" : { "ticketNo" : { "start value" : 1762340000000, "start inclusive" : false, "end value" : 1762352000000, "end inclusive" : false } }
}
]
},
"FROM variable" : "$$bag",
"SELECT expressions" : [
{
"field name" : "fullname",
"field expression" :
{
"iterator kind" : "FIELD_STEP",
"field name" : "fullname",
"input iterator" :
{
"iterator kind" : "VAR_REF",
"variable" : "$$bag"
}
}
},
{
"field name" : "ticketNo",
"field expression" :
{
"iterator kind" : "FIELD_STEP",
"field name" : "ticketNo",
"input iterator" :
{
"iterator kind" : "VAR_REF",
"variable" : "$$bag"
}
}
},
{
"field name" : "tagNum",
"field expression" :
{
"iterator kind" : "ARRAY_CONSTRUCTOR",
"conditional" : true,
"input iterators" : [
{
"iterator kind" : "FIELD_STEP",
"field name" : "tagNum",
"input iterator" :
{
"iterator kind" : "ARRAY_FILTER",
"input iterator" :
{
"iterator kind" : "FIELD_STEP",
"field name" : "bagInfo",
"input iterator" :
{
"iterator kind" : "VAR_REF",
"variable" : "$$bag"
}
}
}
}
]
}
},
{
"field name" : "routing",
"field expression" :
{
"iterator kind" : "ARRAY_CONSTRUCTOR",
"conditional" : true,
"input iterators" : [
{
"iterator kind" : "FIELD_STEP",
"field name" : "routing",
"input iterator" :
{
"iterator kind" : "ARRAY_FILTER",
"input iterator" :
{
"iterator kind" : "FIELD_STEP",
"field name" : "bagInfo",
"input iterator" :
{
"iterator kind" : "VAR_REF",
"variable" : "$$bag"
}
}
}
}
]
}
}
]
}
}
- この問合せ計画のルート・イテレータはRECEIVEイテレータで、子が1つ(入力イテレータ)あり、それはSELECTイテレータです。
FROM
フィールドの値がイテレータです。このケースではTABLEイテレータとなります。- 主キー索引が使用され、これはカバー索引ではありません(表をスキャンして索引エントリ以外の列をフェッチする必要があるため)。
- index scansプロパティには、実行する索引スキャンを定義する開始条件と停止条件が含まれます。
- FROM変数は、FROMイテレータによって生成されるレコード全体にわたる変数の名前です。ここではFROMイテレータはTABLEイテレータで、FROM変数(
$$bag
)は、使用する索引がカバー索引ではないため、TABLEイテレータのrow variableと同じになります。 - SELECT式では、4つのフィールド(
fullname,ticketNo,bag.bagInfo[].tagNum,bag.bagInfo[].routing
)がフェッチされます。これらは、SELECT式句の4つのフィールド名およびフィールド式に対応します。最初の2つのフィールドについては、フィールド式がFIELD_STEP
イテレータを使用して計算されます。最後の2つのフィールドについては、対応する配列を反復処理するARRAY_CONSTRUCTOR
イテレータを使用してフィールド値がフェッチされます。
問合せ2: 索引条件での主キー索引の使用
SELECT fullname, ticketNo, bag.bagInfo[].tagNum,bag.bagInfo[].routing
FROM BaggageInfo bag WHERE ticketNo > 1762340000000 OR ticketNo < 1762352000000;
{
"iterator kind" : "RECEIVE",
"distribution kind" : "ALL_PARTITIONS",
"input iterator" :
{
"iterator kind" : "SELECT",
"FROM" :
{
"iterator kind" : "TABLE",
"target table" : "BaggageInfo",
"row variable" : "$$bag",
"index used" : "primary index",
"covering index" : false,
"index scans" : [
{
"equality conditions" : {},
"range conditions" : {}
}
],
"index filtering predicate" :
{
"iterator kind" : "OR",
"input iterators" : [
{
"iterator kind" : "GREATER_THAN",
"left operand" :
{
"iterator kind" : "FIELD_STEP",
"field name" : "ticketNo",
"input iterator" :
{
"iterator kind" : "VAR_REF",
"variable" : "$$bag"
}
},
"right operand" :
{
"iterator kind" : "CONST",
"value" : 1762340000000
}
},
{
"iterator kind" : "LESS_THAN",
"left operand" :
{
"iterator kind" : "FIELD_STEP",
"field name" : "ticketNo",
"input iterator" :
{
"iterator kind" : "VAR_REF",
"variable" : "$$bag"
}
},
"right operand" :
{
"iterator kind" : "CONST",
"value" : 1762352000000
}
}
]
}
},
"FROM variable" : "$$bag",
"SELECT expressions" : [
{
"field name" : "fullname",
"field expression" :
{
"iterator kind" : "FIELD_STEP",
"field name" : "fullname",
"input iterator" :
{
"iterator kind" : "VAR_REF",
"variable" : "$$bag"
}
}
},
{
"field name" : "ticketNo",
"field expression" :
{
"iterator kind" : "FIELD_STEP",
"field name" : "ticketNo",
"input iterator" :
{
"iterator kind" : "VAR_REF",
"variable" : "$$bag"
}
}
},
{
"field name" : "tagNum",
"field expression" :
{
"iterator kind" : "ARRAY_CONSTRUCTOR",
"conditional" : true,
"input iterators" : [
{
"iterator kind" : "FIELD_STEP",
"field name" : "tagNum",
"input iterator" :
{
"iterator kind" : "ARRAY_FILTER",
"input iterator" :
{
"iterator kind" : "FIELD_STEP",
"field name" : "bagInfo",
"input iterator" :
{
"iterator kind" : "VAR_REF",
"variable" : "$$bag"
}
}
}
}
]
}
},
{
"field name" : "routing",
"field expression" :
{
"iterator kind" : "ARRAY_CONSTRUCTOR",
"conditional" : true,
"input iterators" : [
{
"iterator kind" : "FIELD_STEP",
"field name" : "routing",
"input iterator" :
{
"iterator kind" : "ARRAY_FILTER",
"input iterator" :
{
"iterator kind" : "FIELD_STEP",
"field name" : "bagInfo",
"input iterator" :
{
"iterator kind" : "VAR_REF",
"variable" : "$$bag"
}
}
}
}
]
}
}
]
}
}
- この問合せ計画のルート・イテレータはRECEIVEイテレータで、子が1つ(入力イテレータ)あり、それはSELECTイテレータです。
FROM
フィールドの値がイテレータです。このケースではTABLEイテレータとなります。- 主キー索引が使用され、これはカバー索引ではありません(表をスキャンして索引エントリ以外の列をフェッチする必要があるため)。
index filtering predicate
は、ticketNo
フィールドのフィルタ基準を評価します。「より大きい」演算子と「より小さい」演算子を使用して、フィルタ条件が評価されます。- FROM変数は、FROMイテレータによって生成されるレコード全体にわたる変数の名前です。ここではFROMイテレータはTABLEイテレータで、FROM変数(
$$bag
)は、使用する索引がカバー索引ではないため、TABLEイテレータのrow variableと同じになります。 - SELECT式では、4つのフィールド(
fullname,ticketNo,bag.bagInfo[].tagNum, bag.bagInfo[].routing
)がフェッチされます。これらは、SELECT式句の4つのフィールド名およびフィールド式に対応します。最初の2つのフィールドについては、フィールド式がFIELD_STEP
イテレータを使用して計算されます。最後の2つのフィールドについては、対応する配列を反復処理するARRAY_CONSTRUCTOR
イテレータを使用してフィールド値がフェッチされます。
問合せ3: 索引レンジ・スキャンでの2次索引の使用
SELECT fullName,bag.ticketNo, bag.confNo, bag.bagInfo[].tagNum,
bag.bagInfo[].routing FROM BaggageInfo bag WHERE bag.confNo="FH7G1W"
{
"iterator kind" : "RECEIVE",
"distribution kind" : "ALL_SHARDS",
"input iterator" :
{
"iterator kind" : "SELECT",
"FROM" :
{
"iterator kind" : "TABLE",
"target table" : "BaggageInfo",
"row variable" : "$$bag",
"index used" : "fixedschema_conf",
"covering index" : false,
"index scans" : [
{
"equality conditions" : {"confNo":"FH7G1W"},
"range conditions" : {}
}
]
},
"FROM variable" : "$$bag",
"SELECT expressions" : [
{
"field name" : "fullName",
"field expression" :
{
"iterator kind" : "FIELD_STEP",
"field name" : "fullName",
"input iterator" :
{
"iterator kind" : "VAR_REF",
"variable" : "$$bag"
}
}
},
{
"field name" : "ticketNo",
"field expression" :
{
"iterator kind" : "FIELD_STEP",
"field name" : "ticketNo",
"input iterator" :
{
"iterator kind" : "VAR_REF",
"variable" : "$$bag"
}
}
},
{
"field name" : "confNo",
"field expression" :
{
"iterator kind" : "FIELD_STEP",
"field name" : "confNo",
"input iterator" :
{
"iterator kind" : "VAR_REF",
"variable" : "$$bag"
}
}
},
{
"field name" : "tagNum",
"field expression" :
{
"iterator kind" : "ARRAY_CONSTRUCTOR",
"conditional" : true,
"input iterators" : [
{
"iterator kind" : "FIELD_STEP",
"field name" : "tagNum",
"input iterator" :
{
"iterator kind" : "ARRAY_FILTER",
"input iterator" :
{
"iterator kind" : "FIELD_STEP",
"field name" : "bagInfo",
"input iterator" :
{
"iterator kind" : "VAR_REF",
"variable" : "$$bag"
}
}
}
}
]
}
},
{
"field name" : "routing",
"field expression" :
{
"iterator kind" : "ARRAY_CONSTRUCTOR",
"conditional" : true,
"input iterators" : [
{
"iterator kind" : "FIELD_STEP",
"field name" : "routing",
"input iterator" :
{
"iterator kind" : "ARRAY_FILTER",
"input iterator" :
{
"iterator kind" : "FIELD_STEP",
"field name" : "bagInfo",
"input iterator" :
{
"iterator kind" : "VAR_REF",
"variable" : "$$bag"
}
}
}
}
]
}
}
]
}
}
- この問合せ計画のルート・イテレータはRECEIVEイテレータで、子が1つ(入力イテレータ)あり、それはSELECTイテレータです。
FROM
フィールドの値がイテレータです。このケースではTABLEイテレータとなります。- 索引
fixedschema_conf
が使用され、これはカバー索引ではありません(表をスキャンして索引エントリ以外の列をフェッチする必要があるため)。 - index scansプロパティには、実行する索引スキャンを定義する開始条件と停止条件が含まれます。
- FROM変数は、FROMイテレータによって生成されるレコード全体にわたる変数の名前です。ここではFROMイテレータはTABLEイテレータで、FROM変数(
$$bag
)は、使用する索引がカバー索引ではないため、TABLEイテレータのrow variableと同じになります。 - SELECT式では、4つのフィールド(
fullname,ticketNo,confNo,bag.bagInfo[].tagNum,bag.bagInfo[].routing
)がフェッチされます。これらは、SELECT式句の5つのフィールド名およびフィールド式に対応します。最初の3つのフィールドについては、フィールド式がFIELD_STEP
イテレータを使用して計算されます。最後の2つのフィールドについては、対応する配列を反復処理するARRAY_CONSTRUCTOR
イテレータを使用してフィールド値がフェッチされます。
問合せ4: 主索引の使用
SELECT fullname,bag.bagInfo[].routing FROM BaggageInfo bag
WHERE gender!="F"
{
"iterator kind" : "RECEIVE",
"distribution kind" : "ALL_PARTITIONS",
"input iterator" :
{
"iterator kind" : "SELECT",
"FROM" :
{
"iterator kind" : "TABLE",
"target table" : "BaggageInfo",
"row variable" : "$$bag",
"index used" : "primary index",
"covering index" : false,
"index scans" : [
{
"equality conditions" : {},
"range conditions" : {}
}
]
},
"FROM variable" : "$$bag",
"WHERE" :
{
"iterator kind" : "NOT_EQUAL",
"left operand" :
{
"iterator kind" : "FIELD_STEP",
"field name" : "gender",
"input iterator" :
{
"iterator kind" : "VAR_REF",
"variable" : "$$bag"
}
},
"right operand" :
{
"iterator kind" : "CONST",
"value" : "F"
}
},
"SELECT expressions" : [
{
"field name" : "fullname",
"field expression" :
{
"iterator kind" : "FIELD_STEP",
"field name" : "fullname",
"input iterator" :
{
"iterator kind" : "VAR_REF",
"variable" : "$$bag"
}
}
},
{
"field name" : "routing",
"field expression" :
{
"iterator kind" : "ARRAY_CONSTRUCTOR",
"conditional" : true,
"input iterators" : [
{
"iterator kind" : "FIELD_STEP",
"field name" : "routing",
"input iterator" :
{
"iterator kind" : "ARRAY_FILTER",
"input iterator" :
{
"iterator kind" : "FIELD_STEP",
"field name" : "bagInfo",
"input iterator" :
{
"iterator kind" : "VAR_REF",
"variable" : "$$bag"
}
}
}
}
]
}
}
]
}
}
- この問合せ計画のルート・イテレータはRECEIVEイテレータで、子が1つ(入力イテレータ)あり、それはSELECTイテレータです。
FROM
フィールドの値がイテレータです。このケースではTABLEイテレータとなります。- 主キー索引が使用され、これはカバー索引ではありません(表をスキャンして索引エントリ以外の列をフェッチする必要があるため)。
- FROM変数は、FROMイテレータによって生成されるレコード全体にわたる変数の名前です。ここではFROMイテレータはTABLEイテレータで、FROM変数(
$$bag
)は、使用する索引がカバー索引ではないため、TABLEイテレータのrow variableと同じになります。 - SELECT式では、2つのフィールド(
fullname,bag.bagInfo[].routing
)がフェッチされます。これらは、SELECT式句の2つのフィールド名およびフィールド式に対応します。最初のフィールドについては、フィールド式がFIELD_STEP
イテレータを使用して計算されます。2つ目のフィールドについては、対応する配列を反復処理するARRAY_CONSTRUCTOR
イテレータを使用してフィールド値がフェッチされます。
問合せ5: カバー索引を使用したデータのソート
SELECT bag.contactPhone, bag.fullName FROM BaggageInfo bag
ORDER BY bag.fullName
{
"iterator kind" : "RECEIVE",
"distribution kind" : "ALL_SHARDS",
"order by fields at positions" : [ 1 ],
"input iterator" :
{
"iterator kind" : "SELECT",
"FROM" :
{
"iterator kind" : "TABLE",
"target table" : "BaggageInfo",
"row variable" : "$$bag",
"index used" : "compindex_namephone",
"covering index" : true,
"index row variable" : "$$bag_idx",
"index scans" : [
{
"equality conditions" : {},
"range conditions" : {}
}
]
},
"FROM variable" : "$$bag_idx",
"SELECT expressions" : [
{
"field name" : "contactPhone",
"field expression" :
{
"iterator kind" : "FIELD_STEP",
"field name" : "contactPhone",
"input iterator" :
{
"iterator kind" : "VAR_REF",
"variable" : "$$bag_idx"
}
}
},
{
"field name" : "fullName",
"field expression" :
{
"iterator kind" : "FIELD_STEP",
"field name" : "fullName",
"input iterator" :
{
"iterator kind" : "VAR_REF",
"variable" : "$$bag_idx"
}
}
}
]
}
}
- この問合せ計画のルート・イテレータはRECEIVEイテレータで、子が1つ(入力イテレータ)あり、それはSELECTイテレータです。この例のRECEIVEイテレータのプロパティは、値がALL_SHARDSであるdistribution kindのみです。
- 結果を
fullName
でソートする必要があります。fullName
は、compindex_namephone
索引の一部です。そのため、この例では、個別のSORT演算子は必要ありません。ソートは、RECEIVE演算子で、配列であるプロパティorder by fields at positions
を使用して実行されます。この配列の値は、SELECT式でソートされるフィールドの位置によって異なります。"order by fields at positions" : [ 1 ]
- この例では、SELECT式の2番目のフィールドである
fullName
を使用して、order byが実行されます。そのため、イテレータのorder by fields at position
プロパティには1
が表示されています。 - ここでは、索引
compindex_namephone
が使用されます。この例では索引のエントリのみを使用して問合せを評価できるため、この索引はカバー索引です。 - index row variableは
$$bag_idx
で、これはTABLEイテレータによって生成された索引エントリ全体にわたる変数の名前です。新しい索引エントリが索引スキャンによって生成されるたびに、$$bag_idx
変数がそのエントリにバインドされます。 - FROMイテレータがTABLEイテレータの場合、FROM変数は、使用されている索引がカバー索引かどうかに応じて、TABLEイテレータのindex row variableまたはrow variableのいずれかと同じになります。この例では、索引がカバー索引であるため、FROM変数はindex row variable (
$$bag_idx
)と同じです。 - このindex row variable (
$$bag_idx
)は、SELECT式の他の句を実装するイテレータによって参照されます。 - SELECT式では、2つのフィールド(
contactPhone,fullName
)がフェッチされます。これらは、SELECT式句の2つのフィールド名およびフィールド式に対応します。両方のフィールドについて、フィールド式がFIELD_STEP
イテレータを使用して計算されます。
問合せ6: 索引条件での2次索引の使用
SELECT fullName, bag.ticketNo, bag.bagInfo[].bagArrivalDate
FROM BaggageInfo bag WHERE EXISTS
bag.bagInfo[$element.bagArrivalDate >="2019-01-01T00:00:00"]
{
"iterator kind" : "RECEIVE",
"distribution kind" : "ALL_SHARDS",
"distinct by fields at positions" : [ 1 ],
"input iterator" :
{
"iterator kind" : "SELECT",
"FROM" :
{
"iterator kind" : "TABLE",
"target table" : "BaggageInfo",
"row variable" : "$$bag",
"index used" : "simpleindex_arrival",
"covering index" : false,
"index row variable" : "$$bag_idx",
"index scans" : [
{
"equality conditions" : {},
"range conditions" : {}
}
],
"index filtering predicate" :
{
"iterator kind" : "GREATER_OR_EQUAL",
"left operand" :
{
"iterator kind" : "FIELD_STEP",
"field name" : "bagInfo[].bagArrivalDate",
"input iterator" :
{
"iterator kind" : "VAR_REF",
"variable" : "$$bag_idx"
}
},
"right operand" :
{
"iterator kind" : "CONST",
"value" : "2019-01-01T00:00:00"
}
}
},
"FROM variable" : "$$bag",
"SELECT expressions" : [
{
"field name" : "fullName",
"field expression" :
{
"iterator kind" : "FIELD_STEP",
"field name" : "fullName",
"input iterator" :
{
"iterator kind" : "VAR_REF",
"variable" : "$$bag"
}
}
},
{
"field name" : "ticketNo",
"field expression" :
{
"iterator kind" : "FIELD_STEP",
"field name" : "ticketNo",
"input iterator" :
{
"iterator kind" : "VAR_REF",
"variable" : "$$bag"
}
}
},
{
"field name" : "bagArrivalDate",
"field expression" :
{
"iterator kind" : "ARRAY_CONSTRUCTOR",
"conditional" : true,
"input iterators" : [
{
"iterator kind" : "FIELD_STEP",
"field name" : "bagArrivalDate",
"input iterator" :
{
"iterator kind" : "ARRAY_FILTER",
"input iterator" :
{
"iterator kind" : "FIELD_STEP",
"field name" : "bagInfo",
"input iterator" :
{
"iterator kind" : "VAR_REF",
"variable" : "$$bag"
}
}
}
}
]
}
}
]
}
}
- この問合せ計画のルート・イテレータはRECEIVEイテレータで、子が1つ(入力イテレータ)あり、それはSELECTイテレータです。
FROM
フィールドの値がイテレータです。このケースではTABLEイテレータとなります。- EXISTS条件は、実際にはフィルタリング条件に変換されます。1つのフィルタリング条件(つまりWHERE式全体)が存在します。ここでは、索引
simpleindex_arrival
のみが適用可能な索引であり、使用されています。 index filtering predicate
は、bagArrivalDate
フィールドのフィルタ基準を評価します。「より大きい」演算子と「より小さい」演算子を使用して、フィルタ条件が評価されます。- FROM変数は、FROMイテレータによって生成されるレコード全体にわたる変数の名前です。ここではFROMイテレータはTABLEイテレータで、FROM変数(
$$bag
)は、使用する索引がカバー索引ではないため、TABLEイテレータのrow variableと同じになります。 - SELECT式では、3つのフィールド(
fullname, ticketNo,bag.bagInfo[].bagArrivalDat
)がフェッチされます。これらは、SELECT式句の3つのフィールド名およびフィールド式に対応します。最初の2つのフィールドについては、フィールド式がFIELD_STEP
イテレータを使用して計算されます。最後のフィールドについては、対応する配列を反復処理するARRAY_CONSTRUCTOR
イテレータを使用してフィールド値がフェッチされます。
問合せ7: 索引の一部であるフィールドによるデータのグループ化
SELECT bag.confNo, count(bag.bagInfo) AS TOTAL_BAGS
FROM BaggageInfo bag GROUP BY bag.confNo;
{
"iterator kind" : "SELECT",
"FROM" :
{
"iterator kind" : "RECEIVE",
"distribution kind" : "ALL_SHARDS",
"order by fields at positions" : [ 0 ],
"input iterator" :
{
"iterator kind" : "SELECT",
"FROM" :
{
"iterator kind" : "TABLE",
"target table" : "BaggageInfo",
"row variable" : "$$bag",
"index used" : "fixedschema_conf",
"covering index" : false,
"index scans" : [
{
"equality conditions" : {},
"range conditions" : {}
}
]
},
"FROM variable" : "$$bag",
"GROUP BY" : "Grouping by the first expression in the SELECT list",
"SELECT expressions" : [
{
"field name" : "confNo",
"field expression" :
{
"iterator kind" : "FIELD_STEP",
"field name" : "confNo",
"input iterator" :
{
"iterator kind" : "VAR_REF",
"variable" : "$$bag"
}
}
},
{
"field name" : "TOTAL_BAGS",
"field expression" :
{
"iterator kind" : "FN_COUNT",
"input iterator" :
{
"iterator kind" : "FIELD_STEP",
"field name" : "bagInfo",
"input iterator" :
{
"iterator kind" : "VAR_REF",
"variable" : "$$bag"
}
}
}
}
]
}
},
"FROM variable" : "$from-1",
"GROUP BY" : "Grouping by the first expression in the SELECT list",
"SELECT expressions" : [
{
"field name" : "confNo",
"field expression" :
{
"iterator kind" : "FIELD_STEP",
"field name" : "confNo",
"input iterator" :
{
"iterator kind" : "VAR_REF",
"variable" : "$from-1"
}
}
},
{
"field name" : "TOTAL_BAGS",
"field expression" :
{
"iterator kind" : "FUNC_SUM",
"input iterator" :
{
"iterator kind" : "FIELD_STEP",
"field name" : "TOTAL_BAGS",
"input iterator" :
{
"iterator kind" : "VAR_REF",
"variable" : "$from-1"
}
}
}
}
]
}
- この問合せでは、乗客の
confNo
に基づいてすべての手荷物をグループ化し、各confNo
に属する手荷物の合計数を決定します。 - group-byは索引ベースです。つまり、group-byフィールド(
confNo
)は使用される索引の一部でもあります。このことはGROUPイテレータがないことによって示されています。かわりに、SELECTイテレータによってグループ化が行われます。 - 2つのSELECTイテレータがあり、内側のイテレータには、どのSELECT句式がグループ化式でもあるかを指定する
GROUP BY
プロパティがあります。ここでは、group byフィールドは、SELECTリストの最初の式(bag.confNo
)です。"GROUP BY" : "Grouping by the first expression in the SELECT list"
- ここでは索引
fixedschema_conf
が使用され、この例ではこれはカバー索引ではありません(索引のエントリの外部にあるcount(bag.bagInfo)
も問合せでフェッチする必要があるため)。 - FROMイテレータがTABLEイテレータの場合、FROM変数は、使用されている索引がカバー索引かどうかに応じて、TABLEイテレータのindex row variableまたはrow variableのいずれかと同じになります。この例ではカバー索引ではないため、内側のFROM変数はrow variable (
$$bag
)と同じになります。 - SELECT式では、2つのフィールド(
bag.confNo,count(bag.bagInfo)
)がフェッチされます。これらは、SELECT式句の2つのフィールド名およびフィールド式に対応します。 - 内側のSELECTイテレータによって様々なRNから返される結果は部分グループです。これは、同じ
bag.confNo
の行が複数のRNに存在する場合があるためです。そのため、再グループ化および再集計はドライバで実行する必要があります。これは、外側のSELECTイテレータ(RECEIVEイテレータの上にある)によって行われます。 - 結果は、
confNo
でソートも行われます。order by fields at positions
プロパティは、ソートに使用するフィールドを指定します。この配列の値は、SELECT式でソートされるフィールドの位置によって異なります。この例では、bag.confNo
はSELECT式の最初のフィールドです。そのため、order by fields at positions
では配列索引0
を使用します。"order by fields at positions" : [ 0 ]
- 外側のSELECT式では、2つのフィールド(
bag.confNo,count(bag.bagInfo)
)がフェッチされます。$from-1
FROM変数は、外側のSELECT式の他の句を実装するイテレータによって参照されます。これらは、外側のSELECT式句の2つのフィールド名およびフィールド式に対応します。最初のフィールドについては、フィールド式でFIELD_STEP
イテレータが使用されます。2番目のフィールドは、集計ファンクションcount
です。イテレータFUNC_SUM
は、親イテレータによって生成された結果を反復処理して手荷物の合計数を決定するために使用されます。
問合せ8: 複数の索引スキャンでの2次索引の使用
SELECT bagdet.fullName, bagdet.bagInfo[].tagNum
FROM BaggageInfo bagdet WHERE bagdet.fullName IN
("Lucinda Beckman", "Adam Phillips",
"Zina Christenson","Fallon Clements");
{
"iterator kind" : "SELECT",
"FROM" :
{
"iterator kind" : "RECEIVE",
"distribution kind" : "ALL_SHARDS",
"order by fields at positions" : [ 0 ],
"input iterator" :
{
"iterator kind" : "SELECT",
"FROM" :
{
"iterator kind" : "TABLE",
"target table" : "BaggageInfo",
"row variable" : "$$bag",
"index used" : "fixedschema_conf",
"covering index" : false,
"index scans" : [
{
"equality conditions" : {},
"range conditions" : {}
}
]
},
"FROM variable" : "$$bag",
"GROUP BY" : "Grouping by the first expression in the SELECT list",
"SELECT expressions" : [
{
"field name" : "confNo",
"field expression" :
{
"iterator kind" : "FIELD_STEP",
"field name" : "confNo",
"input iterator" :
{
"iterator kind" : "VAR_REF",
"variable" : "$$bag"
}
}
},
{
"field name" : "TOTAL_BAGS",
"field expression" :
{
"iterator kind" : "FN_COUNT",
"input iterator" :
{
"iterator kind" : "FIELD_STEP",
"field name" : "bagInfo",
"input iterator" :
{
"iterator kind" : "VAR_REF",
"variable" : "$$bag"
}
}
}
}
]
}
},
"FROM variable" : "$from-1",
"GROUP BY" : "Grouping by the first expression in the SELECT list",
"SELECT expressions" : [
{
"field name" : "confNo",
"field expression" :
{
"iterator kind" : "FIELD_STEP",
"field name" : "confNo",
"input iterator" :
{
"iterator kind" : "VAR_REF",
"variable" : "$from-1"
}
}
},
{
"field name" : "TOTAL_BAGS",
"field expression" :
{
"iterator kind" : "FUNC_SUM",
"input iterator" :
{
"iterator kind" : "FIELD_STEP",
"field name" : "TOTAL_BAGS",
"input iterator" :
{
"iterator kind" : "VAR_REF",
"variable" : "$from-1"
}
}
}
}
]
}
- この問合せ計画のルート・イテレータはRECEIVEイテレータで、子が1つ(入力イテレータ)あり、それはSELECTイテレータです。
FROM
フィールドの値がイテレータです。このケースではTABLEイテレータとなります。- 索引
compindex_namephone
が使用され、これはカバー索引ではありません(表をスキャンして索引エントリ以外の列をフェッチする必要があるため)。 - IN句のすべての値が、等価条件を持つ索引スキャンを使用して評価されます。実行される索引スキャンは4つあり、それぞれが1つの等価条件を評価します。
- FROM変数は、FROMイテレータによって生成されるレコード全体にわたる変数の名前です。ここではFROMイテレータはTABLEイテレータで、FROM変数(
$$bagdet
)は、使用する索引がカバー索引ではないため、TABLEイテレータのrow variableと同じになります。 - SELECT式では、2つのフィールド(
fullname, bag.bagInfo[].tagNum
)がフェッチされます。これらは、SELECT式句の2つのフィールド名およびフィールド式に対応します。最初のフィールドについては、フィールド式がFIELD_STEP
イテレータを使用して計算されます。2つ目のフィールドについては、対応する配列を反復処理するARRAY_CONSTRUCTOR
イテレータを使用してフィールド値がフェッチされます。
問合せ9: 主索引を使用したSINGLE PARTITION問合せ
SELECT fullName,bag.ticketNo, bag.confNo, bag.bagInfo[].tagNum,
bag.bagInfo[].routing FROM BaggageInfo bag WHERE
bag.ticketNo=1762311547917 AND bag.confNo="FH7G1W"
{
"iterator kind" : "RECEIVE",
"distribution kind" : "SINGLE_PARTITION",
"input iterator" :
{
"iterator kind" : "SELECT",
"FROM" :
{
"iterator kind" : "TABLE",
"target table" : "BaggageInfo",
"row variable" : "$$bag",
"index used" : "primary index",
"covering index" : false,
"index scans" : [
{
"equality conditions" : {"ticketNo":1762311547917},
"range conditions" : {}
}
]
},
"FROM variable" : "$$bag",
"WHERE" :
{
"iterator kind" : "EQUAL",
"left operand" :
{
"iterator kind" : "FIELD_STEP",
"field name" : "confNo",
"input iterator" :
{
"iterator kind" : "VAR_REF",
"variable" : "$$bag"
}
},
"right operand" :
{
"iterator kind" : "CONST",
"value" : "FH7G1W"
}
},
"SELECT expressions" : [
{
"field name" : "fullName",
"field expression" :
{
"iterator kind" : "FIELD_STEP",
"field name" : "fullName",
"input iterator" :
{
"iterator kind" : "VAR_REF",
"variable" : "$$bag"
}
}
},
{
"field name" : "ticketNo",
"field expression" :
{
"iterator kind" : "FIELD_STEP",
"field name" : "ticketNo",
"input iterator" :
{
"iterator kind" : "VAR_REF",
"variable" : "$$bag"
}
}
},
{
"field name" : "confNo",
"field expression" :
{
"iterator kind" : "FIELD_STEP",
"field name" : "confNo",
"input iterator" :
{
"iterator kind" : "VAR_REF",
"variable" : "$$bag"
}
}
},
{
"field name" : "tagNum",
"field expression" :
{
"iterator kind" : "ARRAY_CONSTRUCTOR",
"conditional" : true,
"input iterators" : [
{
"iterator kind" : "FIELD_STEP",
"field name" : "tagNum",
"input iterator" :
{
"iterator kind" : "ARRAY_FILTER",
"input iterator" :
{
"iterator kind" : "FIELD_STEP",
"field name" : "bagInfo",
"input iterator" :
{
"iterator kind" : "VAR_REF",
"variable" : "$$bag"
}
}
}
}
]
}
},
{
"field name" : "routing",
"field expression" :
{
"iterator kind" : "ARRAY_CONSTRUCTOR",
"conditional" : true,
"input iterators" : [
{
"iterator kind" : "FIELD_STEP",
"field name" : "routing",
"input iterator" :
{
"iterator kind" : "ARRAY_FILTER",
"input iterator" :
{
"iterator kind" : "FIELD_STEP",
"field name" : "bagInfo",
"input iterator" :
{
"iterator kind" : "VAR_REF",
"variable" : "$$bag"
}
}
}
}
]
}
}
]
}
}
- この問合せ計画のルート・イテレータはRECEIVEイテレータで、子が1つ(入力イテレータ)あり、それはSELECTイテレータです。
- この問合せでは、WHERE句に完全シャード・キーを指定します。その結果、結果セット全体が単一のパーティションに含まれ、RECEIVEイテレータはそのパーティションを格納する単一のRNにサブプランを送信します。
FROM
フィールドの値がイテレータです。このケースではTABLEイテレータとなります。- SINGLE_PARTITION問合せでは、主索引または2次索引を参照できます。この例では、主キー索引が使用されています。これはカバー索引ではありません(表をスキャンして索引エントリ以外の列をフェッチする必要があるため)。
- index scansプロパティには、実行する索引スキャンを定義する開始条件と停止条件が含まれます。
- FROM変数は、FROMイテレータによって生成されるレコード全体にわたる変数の名前です。ここではFROMイテレータはTABLEイテレータで、FROM変数(
$$bag
)は、使用する索引がカバー索引ではないため、TABLEイテレータのrow variableと同じになります。 - SELECT式では、5つのフィールド(
fullname, ticketNo,confNo, bag.bagInfo[].tagNum,bag.bagInfo[].routing
)がフェッチされます。これらは、SELECT式句の5つのフィールド名およびフィールド式に対応します。最初の3つのフィールドについては、フィールド式がFIELD_STEP
イテレータを使用して計算されます。最後の2つのフィールドについては、対応する配列を反復処理するARRAY_CONSTRUCTOR
イテレータを使用してフィールド値がフェッチされます。
問合せ10: 索引の一部ではないフィールドによるデータのグループ化
SELECT $flt_src as SOURCE, count(*) as COUNT FROM BaggageInfo $bag,
$bag.bagInfo.flightLegs[0].fltRouteSrc $flt_src GROUP BY $flt_src
{
"iterator kind" : "GROUP",
"input variable" : "$gb-2",
"input iterator" :
{
"iterator kind" : "RECEIVE",
"distribution kind" : "ALL_PARTITIONS",
"input iterator" :
{
"iterator kind" : "GROUP",
"input variable" : "$gb-1",
"input iterator" :
{
"iterator kind" : "SELECT",
"FROM" :
{
"iterator kind" : "TABLE",
"target table" : "BaggageInfo",
"row variable" : "$bag",
"index used" : "primary index",
"covering index" : false,
"index scans" : [
{
"equality conditions" : {},
"range conditions" : {}
}
]
},
"FROM variable" : "$bag",
"FROM" :
{
"iterator kind" : "FIELD_STEP",
"field name" : "fltRouteSrc",
"input iterator" :
{
"iterator kind" : "ARRAY_SLICE",
"low bound" : 0,
"high bound" : 0,
"input iterator" :
{
"iterator kind" : "FIELD_STEP",
"field name" : "flightLegs",
"input iterator" :
{
"iterator kind" : "FIELD_STEP",
"field name" : "bagInfo",
"input iterator" :
{
"iterator kind" : "VAR_REF",
"variable" : "$bag"
}
}
}
}
},
"FROM variable" : "$flt_src",
"SELECT expressions" : [
{
"field name" : "SOURCE",
"field expression" :
{
"iterator kind" : "VAR_REF",
"variable" : "$flt_src"
}
},
{
"field name" : "COUNT",
"field expression" :
{
"iterator kind" : "CONST",
"value" : 1
}
}
]
},
"grouping expressions" : [
{
"iterator kind" : "FIELD_STEP",
"field name" : "SOURCE",
"input iterator" :
{
"iterator kind" : "VAR_REF",
"variable" : "$gb-1"
}
}
],
"aggregate functions" : [
{
"iterator kind" : "FUNC_COUNT_STAR"
}
]
}
},
"grouping expressions" : [
{
"iterator kind" : "FIELD_STEP",
"field name" : "SOURCE",
"input iterator" :
{
"iterator kind" : "VAR_REF",
"variable" : "$gb-2"
}
}
],
"aggregate functions" : [
{
"iterator kind" : "FUNC_SUM",
"input iterator" :
{
"iterator kind" : "FIELD_STEP",
"field name" : "COUNT",
"input iterator" :
{
"iterator kind" : "VAR_REF",
"variable" : "$gb-2"
}
}
}
]
}
- この問合せでは、フライト出発地に基づいて旅客手荷物をグループ化し、1つのフライト出発地に属する手荷物の合計数を決定します。
- GROUP BYフィールド(この例では
bagInfo.flightLegs[0].fltRouteSrc
)はどの索引にも含まれていないため、グループ化を実行するには個別のGROUP演算子が必要です。このことは実行計画にGROUPイテレータが存在することによって示されています。2つのGROUPイテレータがあります。1つ(RECEIVEイテレータの上にある)はドライバで動作し、もう1つ(RECEIVEイテレータの下にある)はRNで動作します。 - 下位のGROUPイテレータの入力はSELECTイテレータです。このSELECTは、手荷物の
fltRouteSrc
およびcount
を返します。GROUPイテレータは、バッチ制限に達するまで動作します。バッチ制限が、生成される結果の最大数Nとして定義されている場合、最大N個のフライト出発地グループが作成されると、GROUPイテレータが停止します。バッチ制限が最大読取りバイト数として定義されている場合、この最大値に達すると停止します。GROUP演算子には入力変数があります。内側のGROUP演算子では、入力変数は$gb-1
で、外側のGROUP演算子では$gb-2
です。"iterator kind" : "GROUP","input variable" : "$gb-1",
- ここでは主キー索引が使用され、この例では、これはカバー索引ではありません(主索引のエントリに含まれないフィールドが問合せにあるため)。
- FROMイテレータがTABLEイテレータの場合、FROM変数は、使用されている索引がカバー索引かどうかに応じて、TABLEイテレータのindex row variableまたはrow variableのいずれかと同じになります。FROMイテレータに対するnext()コールがtrueを返すたびに、そのイテレータによって生成された結果に変数がバインドされます。この例ではカバー索引ではないため、FROM変数はrow variableになります。
- このrow variable (
$bag
)は、内側のSELECT式の他の句を実装するイテレータによって参照されます。 - GROUPイテレータは、SELECT式で生成されたレコードを反復処理する内部変数(
$gb-1
)を作成します。 - 下位のGROUPイテレータによって生成される結果セットは部分的です。すべての
fltRouteSrc
グループが含まれるとは限らず、含まれているfltRouteSrc
グループについても、カウントが部分的な合計になることがあります(問合せの実行が停止したときに、特定のfltRouteSrc
の一部の行が取得されていない可能性があるため)。上位のGROUPイテレータは、各RNから部分的な結果を受け取り、最終的なグループ化と集計を実行します。これは下位のGROUPイテレータと同じように動作し、RNからの部分的な結果がなくなるまで動作し続けます。その時点で、完全な最終の結果セットが上位のGROUPイテレータでキャッシュされ、アプリケーションに返されます。 - 上位のGROUPイテレータは、外側のSELECTで生成されたレコードを反復処理する内部変数(
$gb-2
)を作成します。$gb-2
変数には、fltRouteSrc
と、fltRouteSrc
でグループ化されたすべての手荷物の数が含まれます。 - SELECT式では、2つのフィールド(
fltRouteSrc,count(*)
)がフェッチされます。これらは、SELECT式句の2つのフィールド名およびフィールド式に対応します。最初のフィールドについては、フィールド式でFIELD_STEP
イテレータが使用されます。2番目のフィールドは、集計ファンクションcount
です。イテレータFUNC_SUM
は、親イテレータによって生成された結果を反復処理して手荷物の合計数を決定するために使用されます。