例6: カバー索引を使用したデータのグループ化
すべてのユーザーについて、州(state)および市(city)でグループ化して、州(state)、市(city)および収入(income)合計をフェッチします。
SELECT u.address.state, u.address.city, sum(income)
AS income FROM Users u GROUP BY u.address.state, u.address.city
問合せ実行計画:
{
"iterator kind" : "SELECT",
"FROM" :
{
"iterator kind" : "RECEIVE",
"distribution kind" : "ALL_SHARDS",
"order by fields at positions" : [ 0, 1 ],
"input iterator" :
{
"iterator kind" : "SELECT",
"FROM" :
{
"iterator kind" : "TABLE",
"target table" : "Users",
"row variable" : "$$u",
"index used" : "idx_state_city_income",
"covering index" : true,
"index row variable" : "$$u_idx",
"index scans" : [
{
"equality conditions" : {},
"range conditions" : {}
}
]
},
"FROM variable" : "$$u_idx",
"GROUP BY" : "Grouping by the first 2 expressions in the SELECT list",
"SELECT expressions" : [
{
"field name" : "state",
"field expression" :
{
"iterator kind" : "FIELD_STEP",
"field name" : "address.state",
"input iterator" :
{
"iterator kind" : "VAR_REF",
"variable" : "$$u_idx"
}
}
},
{
"field name" : "city",
"field expression" :
{
"iterator kind" : "FIELD_STEP",
"field name" : "address.city",
"input iterator" :
{
"iterator kind" : "VAR_REF",
"variable" : "$$u_idx"
}
}
},
{
"field name" : "income",
"field expression" :
{
"iterator kind" : "FUNC_SUM",
"input iterator" :
{
"iterator kind" : "FIELD_STEP",
"field name" : "income",
"input iterator" :
{
"iterator kind" : "VAR_REF",
"variable" : "$$u_idx"
}
}
}
}
]
}
},
"FROM variable" : "$from-1",
"GROUP BY" : "Grouping by the first 2 expressions in the SELECT list",
"SELECT expressions" : [
{
"field name" : "state",
"field expression" :
{
"iterator kind" : "FIELD_STEP",
"field name" : "state",
"input iterator" :
{
"iterator kind" : "VAR_REF",
"variable" : "$from-1"
}
}
},
{
"field name" : "city",
"field expression" :
{
"iterator kind" : "FIELD_STEP",
"field name" : "city",
"input iterator" :
{
"iterator kind" : "VAR_REF",
"variable" : "$from-1"
}
}
},
{
"field name" : "income",
"field expression" :
{
"iterator kind" : "FUNC_SUM",
"input iterator" :
{
"iterator kind" : "FIELD_STEP",
"field name" : "income",
"input iterator" :
{
"iterator kind" : "VAR_REF",
"variable" : "$from-1"
}
}
}
}
]
}
問合せ実行計画の説明:
- この例では、
state
およびcity
に基づいてユーザーをグループ化してから、グループ化したユーザーのincome
のsumを算出します。 - グループ化は索引ベースであるため、GROUP BYのフィールドは、使用される索引の一部でもあります。これは、GROUPイテレータがないことからもわかります。かわりに、グループ化は
SELECT
イテレータで実行されます。 - 2つのSELECTイテレータがあり、内側のイテレータには、どのSELECT句式がグループ化式でもあるかを指定する
GROUP BY
プロパティがあります。ここで、GROUP BYのフィールドは、SELECTのリスト内の最初の2つの式(u.address.state,u.address.city
)です。"GROUP BY" : "Grouping by the first 2 expressions in the SELECT list"
- ここでは索引
idx_state_city_income
が使用されています。また、この例では、索引のエントリのみを使用して問合せを評価可能であるため、これはカバー索引です。 - index row variableは
$$u_idx
であり、これは、TABLEイテレータによって生成されるすべての索引エントリを対象とする、変数の名前です。索引スキャンによって新しい索引エントリが生成されるたびに、$$u_idx
変数がそのエントリにバインドされます。 - このindex row variable (
$$u_idx
)は、SELECT式の他の句を実装するイテレータによって参照されます。 - このSELECT式では、3つのフィールド(
state
、city
およびsum(income)
)がフェッチされます。これらは、SELECT式の句にある3つのフィールド名およびフィールド式に対応しています。 - 内側のSELECTイテレータによって様々なRN (レプリケーション・ノード)から返される結果は、部分的なグループです。これは、州(state)と市(city)が同一の行が、複数のRNに存在する場合があるためです。そのため、再グループ化および再集計をドライバで実行する必要があります。これは、外側のSELECTイテレータ(RECEIVEイテレータの上)によって実行されます。
- この結果は、
state
およびcity
を基準にソートされます。order by fields at positions
プロパティにより、ソートに使用するフィールドを指定します。この配列の値は、SELECT式でのソートするフィールドの位置によって異なります。この例では、SELECT式において、state
が1番目のフィールドで、city
が2番目のフィールドです。したがって、order by fields at positions
の値は0,1
になります。"order by fields at positions" : [ 0, 1 ]
- 外側のSELECT式では、3つのフィールド(
state
、city
およびsum(income)
)がフェッチされます。FROM
variableである$from-1
は、外側のSELECT式の他の句を実装するイテレータによって参照されます。これは、外側のSELECT式の句にある3つのフィールド名およびフィールド式に対応しています。この例では、フィールド式のうちの2つでそれらのフィールドのみがフェッチされ、1つのフィールド式で関数(sum(income)
)が評価されます。 - このSELECT式で直接フェッチされる2つのフィールドについては、フィールド式がFIELD_STEPイテレータによって計算されます。FIELD_STEPイテレータでは、その入力イテレータで生成されたレコードからフィールド(以下の
state
)の値が抽出され返されます。city
フィールドについても同様です。
SELECT式内の3番目のフィールドは、incomeの合計を算出する関数です。これには、{ "field name" : "state", "field expression" : { "iterator kind" : "FIELD_STEP", "field name" : "state", "input iterator" : { "iterator kind" : "VAR_REF", "variable" : "$from-1" } } }
FUNC_SUM
イテレータが使用されます。income
フィールドの値を反復処理し、その入力イテレータの結果からすべてのincomeの合計を算出します。{ "field name" : "income", "field expression" : { "iterator kind" : "FUNC_SUM", "input iterator" : { "iterator kind" : "FIELD_STEP", "field name" : "income", "input iterator" : { "iterator kind" : "VAR_REF", "variable" : "$from-1" } } } }