例3: 索引スキャンが含まれる問合せ計画での非カバー索引の使用
索引のエントリのみを使用して問合せをすべて評価できない場合、索引は非カバーとなります。
CAに居住しており収入(income)が5000より多いユーザーのID (id)、年齢(age)および収入(income)をフェッチします。
SELECT id, age, income FROM Users u WHERE u.address.state = "CA"
AND income >5000
問合せ実行計画:
{
"iterator kind" : "RECEIVE",
"distribution kind" : "ALL_SHARDS",
"input iterator" :
{
"iterator kind" : "SELECT",
"FROM" :
{
"iterator kind" : "TABLE",
"target table" : "users",
"row variable" : "$$u",
"index used" : "idx_state_city_income",
"covering index" : false,
"index row variable" : "$$u_idx",
"index scans" : [
{
"equality conditions" : {"address.state":"CA"},
"range conditions" : {}
}
],
"index filtering predicate" :
{
"iterator kind" : "GREATER_THAN",
"left operand" :
{
"iterator kind" : "FIELD_STEP",
"field name" : "income",
"input iterator" :
{
"iterator kind" : "VAR_REF",
"variable" : "$$u_idx"
}
},
"right operand" :
{
"iterator kind" : "CONST",
"value" : 5000
}
}
},
"FROM variable" : "$$u",
"SELECT expressions" : [
{
"field name" : "id",
"field expression" :
{
"iterator kind" : "FIELD_STEP",
"field name" : "id",
"input iterator" :
{
"iterator kind" : "VAR_REF",
"variable" : "$$u"
}
}
},
{
"field name" : "age",
"field expression" :
{
"iterator kind" : "FIELD_STEP",
"field name" : "age",
"input iterator" :
{
"iterator kind" : "VAR_REF",
"variable" : "$$u"
}
}
},
{
"field name" : "income",
"field expression" :
{
"iterator kind" : "FIELD_STEP",
"field name" : "income",
"input iterator" :
{
"iterator kind" : "VAR_REF",
"variable" : "$$u"
}
}
}
]
}
}
問合せ実行計画の説明:
- この問合せ計画のルート・イテレータは、SELECTイテレータである単一の子(入力イテレータ)がある、RECEIVEイテレータです。この例でのRECEIVEイテレータの唯一のプロパティは、値がALL_SHARDSであるdistribution kindです。
- ここでは索引
idx_state_city_income
が使用されています。また、この例では、フェッチ対象となるage
フィールドが索引エントリに含まれていないため、これはカバー索引ではありません。 - 索引スキャン・プロパティには、実行する索引スキャンを定義する、開始条件と停止条件が含まれています。
この例では、1つの索引スキャンのみが実行されます。その条件は、その問合せからのu.address.state = "CA"という条件に対応しています。具体的に述べると、開始索引エントリで、"index scans" : [ { "equality conditions" : {"address.state":"CA"}, "range conditions" : {} } ]
address.state
フィールドの値がCAである必要があります。後続のすべてのエントリでそのaddress.state
フィールドの値がCAである必要があり、state値が異なるエントリが検出されるとすぐにスキャンが停止されます。問合せにはincomeの範囲条件が含まれていますが、この条件は索引スキャンの範囲条件として表示されません。これは、索引定義内のincomeフィールドの前にあるaddress.city
フィールドに等価条件がなく、その結果、income条件を使用してスキャンの境界を判断できないためです。かわりに、この索引スキャンによって生成されるすべての索引エントリに適用するindex filtering predicate
として、income条件を使用できます。 index filtering predicate
では、income
フィールドのフィルタ基準が評価されます。より大演算子を使用して、フィルタ条件が評価されます。"index filtering predicate" : { "iterator kind" : "GREATER_THAN", "left operand" : { "iterator kind" : "FIELD_STEP", "field name" : "income", "input iterator" : { "iterator kind" : "VAR_REF", "variable" : "$$u_idx" } }, "right operand" : { "iterator kind" : "CONST", "value" : 5000 } }
- index row variableは
$$u_idx
であり、これは、TABLEイテレータによって生成されるすべての索引エントリを対象とする、変数の名前です。索引スキャンによって新しい索引エントリが生成されるたびに、$$u_idx
変数がそのエントリにバインドされます。 - FROMイテレータがTABLEイテレータである場合、FROM variableは、TABLEイテレータのindex row variableまたはrow variableのどちらか(使用されている索引がカバーかどうかで異なる)と同じになります。この例では、索引がカバーではないため、FROM variableはrow variableと同じになります。
- このrow variable (
$$u
)は、SELECT式の他の句を実装するイテレータによって参照されます。 - このSELECT式では、3つのフィールド(
id
、income
およびage
)がフェッチされます。これらは、SELECT式の句にある3つのフィールド名およびフィールド式に対応しています。
このSELECT式によってフェッチされるフィールドごとに、フィールド式がFIELD_STEPイテレータによって計算されます。FIELD_STEPイテレータでは、その入力イテレータで生成されたレコードからフィールド(前述の{ "field name" : "id", "field expression" : { "iterator kind" : "FIELD_STEP", "field name" : "#id", "input iterator" : { "iterator kind" : "VAR_REF", "variable" : "$$u" } } }
id
)の値が抽出され返されます。このSELECT式でフェッチされるフィールドごとに同じことが実行されます。