例7: 索引に含まれていないフィールドを使用したデータのグループ化

州(state)がCAであるすべてのユーザーについて年齢(age)および収入(income)合計をフェッチし、そのデータをageを基準にグループ化します。
SELECT age, sum(income) FROM Users u 
WHERE u.address.state = "CA" GROUP BY age
問合せ実行計画:
{
  "iterator kind" : "GROUP",
  "input variable" : "$gb-2",
  "input iterator" :
  {
    "iterator kind" : "RECEIVE",
    "distribution kind" : "ALL_SHARDS",
    "input iterator" :
    {
      "iterator kind" : "GROUP",
      "input variable" : "$gb-1",
      "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 scans" : [
            {
              "equality conditions" : {"address.state":"CA"},
              "range conditions" : {}
            }
          ]
        },
        "FROM variable" : "$$u",
        "SELECT expressions" : [
          {
            "field name" : "age",
            "field expression" :
            {
              "iterator kind" : "FIELD_STEP",
              "field name" : "age",
              "input iterator" :
              {
                "iterator kind" : "VAR_REF",
                "variable" : "$$u"
              }
            }
          },
          {
            "field name" : "Column_2",
            "field expression" :
            {
              "iterator kind" : "FIELD_STEP",
              "field name" : "income",
              "input iterator" :
              {
                "iterator kind" : "VAR_REF",
                "variable" : "$$u"
              }
            }
          }
        ]
      },
      "grouping expressions" : [
        {
          "iterator kind" : "FIELD_STEP",
          "field name" : "age",
          "input iterator" :
          {
            "iterator kind" : "VAR_REF",
            "variable" : "$gb-1"
          }
        }
      ],
      "aggregate functions" : [
        {
          "iterator kind" : "FUNC_SUM",
          "input iterator" :
          {
            "iterator kind" : "FIELD_STEP",
            "field name" : "Column_2",
            "input iterator" :
            {
              "iterator kind" : "VAR_REF",
              "variable" : "$gb-1"
            }
          }
        }
      ]
    }
  },
  "grouping expressions" : [
    {
      "iterator kind" : "FIELD_STEP",
      "field name" : "age",
      "input iterator" :
      {
        "iterator kind" : "VAR_REF",
        "variable" : "$gb-2"
      }
    }
  ],
  "aggregate functions" : [
    {
      "iterator kind" : "FUNC_SUM",
      "input iterator" :
      {
        "iterator kind" : "FIELD_STEP",
        "field name" : "Column_2",
        "input iterator" :
        {
          "iterator kind" : "VAR_REF",
          "variable" : "$gb-2"
        }
      }
    }
  ]
}
問合せ実行計画の説明:
  • この例では、州(state)がCAであるすべてのユーザーをその年齢(age)に基づいてグループ化し、各年齢グループに属するユーザーの収入(income)の合計を算出します。
  • GROUP BYのフィールド(この例ではage)はどの索引にも含まれていないため、グループ化を実行するには別個のGROUP演算子が必要です。これは、実行計画にGROUPイテレータが存在することからもわかります。2つのGROUPイテレータがあります。1つはドライバで機能し(RECEIVEイテレータの上)、もう1つはRN (レプリケーション・ノード)で機能します(RECEIVEイテレータの下)。
  • 下のGROUPイテレータには、入力としてSELECTイテレータがあります。このSELECTでは、州(state)がCAである各ユーザーの年齢(age)と収入(income)が返されます。このGROUPイテレータは、バッチ制限に到達するまで機能します。バッチ制限が、生成される結果の最大数Nとして定義されている場合、このGROUPイテレータは、N個まで年齢グループが作成されると停止されます。バッチ制限が最大読取りバイト数として定義されている場合、それは、この最大値に到達すると停止されます。GROUP演算子には入力変数があります。内側のGROUP演算子の場合、入力変数は$gb-1であり、外側のGROUP演算子の場合は$gb-2です。
    "iterator kind" : "GROUP","input variable" : "$gb-1",
  • ここでは索引idx_state_city_incomeが使用されています。また、この例では、索引のエントリにないageフィールドが問合せに含まれているため、これはカバー索引ではありません。
  • 索引スキャン・プロパティには、実行する索引スキャンを定義する、開始条件と停止条件が含まれています。この例では、1つの索引スキャンのみが実行されます。その条件は、u.address.state = "CA"という条件に対応しています。具体的に述べると、開始索引エントリで、address.stateフィールドの値がCAである必要があります。後続のすべてのエントリでそのaddress.stateフィールドの値がCAである必要があり、state値が異なるエントリが検出されるとすぐにスキャンが停止されます。
  • FROMイテレータがTABLEイテレータである場合、FROM variableは、TABLEイテレータのindex row variableまたはrow variableのどちらか(使用されている索引がカバーかどうかで異なる)と同じになります。この例では、索引がカバーではないため、FROM variableはrow variableと同じになります。
  • このrow variable ($$u)は、内側のSELECT式の他の句を実装するイテレータによって参照されます。
  • このGROUPイテレータでは、SELECT式で生成されたレコードを反復処理する内部変数($gb-1)が作成されます。
  • 下のGROUPイテレータによって生成される結果セットは部分的なものです。それにすべての年齢グループが含まれていない場合があり、含まれている年齢グループについては、収入(income)が部分的な合計になる場合があります(問合せ実行の停止時に特定の年齢(age)についてすべての行が取得されていない場合があるため)。上のGROUPイテレータでは、部分的な結果を各RNから受け取って最終的なグループ化と集計が実行されます。これは、下のGROUPイテレータと同様に機能し、RNからの部分的結果の受取りがなくなるまで機能し続けます。その時点で、上のGROUPイテレータで完全かつ最終的な結果セットがキャッシュされ、それがアプリケーションに返されます。
  • 上のGROUPイテレータでは、外側のSELECT式で生成されたレコードを反復処理する内部変数($gb-2)が作成されます。$gb-2変数には、州(state)がCAであるすべてのユーザーについて、ageでグループ化して、年齢(age)と収入(income)合計が含まれています。
  • このSELECT式では、2つのフィールド(ageおよびsum(income))がフェッチされます。これらは、SELECT式の句にある2つのフィールド名およびフィールド式に対応しています。
  • ageフィールドについては、フィールド式がFIELD_STEPイテレータによって計算されます。FIELD_STEPイテレータでは、その入力イテレータで生成されたレコードからageフィールドの値が抽出され返されます。
    {
       "iterator kind" : "FIELD_STEP",
       "field name" : "age",
       "input iterator" :
       {
          "iterator kind" : "VAR_REF",
          "variable" : "$gb-2"
       }
    }
  • フェッチされる2番目のフィールドは、incomeの値の集計関数sumです。これには、FUNC_SUMイテレータが使用されます。incomeフィールドの値を反復処理し、その入力イテレータの結果からすべてのincomeの合計を算出します。
    "aggregate functions" : [
       {
          "iterator kind" : "FUNC_SUM",
          "input iterator" :
          {
            "iterator kind" : "FIELD_STEP",
            "field name" : "Column_2",
            "input iterator" :
            {
              "iterator kind" : "VAR_REF",
              "variable" : "$gb-2"
            }
          }
       }
    ]