クラスター化カラム

クラスター化カラムに対するクエリーを制限して、クラスター化セグメント全体の範囲を検索します。

クラスター化カラムは、パーティション内のデータの順序を決定します。テーブルに複数のクラスター化カラムがある場合、データはネストされたソート順で格納されます。データベースはクラスター化情報を使用してパーティション内のデータの場所を特定します。クラスター化カラムにロジック文を使用してクラスター化セグメントを特定し、データのスライスを返します。

ヒント: 適切に設計されたテーブルはクラスター化カラムを使用して、特定の範囲のデータを返すことができます。「CQLデータ・モデリング」を参照してください。

クラスター化カラムまたはインデックス・カラムに対してクエリーに制限がない場合は、そのパーティションのすべてのデータが返されます。

順序がクラスター化の制限に与える影響

データベースはクラスター化カラムを使用してパーティションのデータの場所を判断するため、等号(=)またはIN演算子を使用して、上位のクラスター化カラムを明確に特定する必要があります。クエリーで、範囲演算子(>、>=、<、<=)を使用して制限できるのは最下位のみです。

データの格納方法

以下のテーブルを使用して、クラスター化の動作を説明します。
CREATE TABLE numbers (
   key int,
   col_1 int,
   col_2 int,
   col_3 int,
   col_4 int,
   PRIMARY KEY ((key), col_1, col_2, col_3, col_4));
この例のテーブルには、以下のデータが含まれています。
 key | col_1 | col_2 | col_3 | col_4
-----+-------+-------+-------+-------
 100 |     1 |     1 |     1 |     1
 100 |     1 |     1 |     1 |     2
 100 |     1 |     1 |     1 |     3
 100 |     1 |     1 |     2 |     1
 100 |     1 |     1 |     2 |     2
 100 |     1 |     1 |     2 |     3
 100 |     1 |     2 |     2 |     1
 100 |     1 |     2 |     2 |     2
 100 |     1 |     2 |     2 |     3
 100 |     2 |     1 |     1 |     1
 100 |     2 |     1 |     1 |     2
 100 |     2 |     1 |     1 |     3
 100 |     2 |     1 |     2 |     1
 100 |     2 |     1 |     2 |     2
 100 |     2 |     1 |     2 |     3
 100 |     2 |     2 |     2 |     1
 100 |     2 |     2 |     2 |     2
 100 |     2 |     2 |     2 |     3

(18 rows)

データベースはネストされたソート順を使用してデータの格納と検索を行います。 データはクエリーが探索する階層に格納されます。

{ "key" : "100"  { 
         "col_1" : "1"  {
                  "col_2" : "1" {
                            "col_3" : "1" { 
                                       "col_4" : "1", 
                                       "col_4" : "2", 
                                        "col_4" : "3"  },
                            "col_3" : "2" {
                                      "col_4" : "1",
                                      "col_4" : "2",
                                      "col_4" : "3"  } }, 
                  "col_2" : "2" {
                            "col_3" : "2" {
                                      "col_4" : "1",
                                      "col_4" : "2",
                                      "col_4" : "3"  } } }, 
         "col_1" : "2"  {
                  "col_2" : "1" {
                            "col_3" : "1" …

パーティションのフルスキャンを避けてクエリーを効率化するには、等号またはIN演算子を使用して、ソート順の上位カラム(col_1、col_2、col_3)を特定する必要があります。最後のカラム(col_4)では範囲を使用できます。

クラスター化セグメントのデータの選択

たとえば、カラム4で2以下の値のみを見つけるには、以下のように入力します。
SELECT * FROM numbers 
WHERE key = 100 
AND col_1 = 1 AND col_2 = 1 AND col_3 = 1
AND col_4 <= 2;
この結果には最初の2行が含まれています。
 key | col_1 | col_2 | col_3 | col_4
-----+-------+-------+-------+-------
 100 |     1 |     1 |     1 |     1
 100 |     1 |     1 |     1 |     2

(2 rows)

IN演算子は中~大規模なデータセットのパフォーマンスに影響を与える場合があります。複数のセグメントを選択すると、指定したすべてのセグメントが読み込まれ、フィルター処理されます。

たとえば、col_1のセグメント1と2の両方で2以下のすべての値を見つけるには、以下のように入力します。
SELECT * FROM numbers 
WHERE key = 100 
AND col_1 IN (1, 2) 
AND col_2 = 1 AND col_3 = 1
AND col_4 <= 2;

以下の図は、複数のセグメントをフィルター処理するためにデータベースで読み込む必要があるすべてのセグメントを示しています。

この結果では、両方のセグメントの範囲が返されます。
 key | col_1 | col_2 | col_3 | col_4
-----+-------+-------+-------+-------
 100 |     1 |     1 |     1 |     1
 100 |     1 |     1 |     1 |     2
 100 |     2 |     1 |     1 |     1
 100 |     2 |     1 |     1 |     2

(4 rows)
ヒント: お使いの環境でさまざまなクエリーへの影響を分析するには、TRACINGを使用します。

無効な制限

上位のセグメントを特定せずに範囲を返そうとするクエリーは拒否されます。
SELECT * FROM numbers 
WHERE key = 100 
AND col_4 <= 2;
この要求は無効です。
InvalidRequest: Error from server: code=2200 [Invalid query] message="PRIMARY KEY column "col_4" 
cannot be restricted as preceding column "col_1" is not restricted"
注意: ALLOW FILTERINGオプションを使用するとクエリーを強制的に実行できますが、これを行うと、パーティション全体を読み込み、読み取り(READ)レイテンシーが長引いて、パフォーマンスに悪影響を及ぼします。

最上位のクラスター化カラムのみを制限する

パーティション・カラムと異なり、クエリーのロジック文で下位のクラスター化カラムを除外することができます。

たとえば、中位のカラムの1つをフィルター処理するには、等号またはINを使用して最初のレベルのカラムを制限し、次に2番目のレベルで範囲を指定します。
SELECT * FROM numbers 
WHERE key = 100 AND col_1 = 1
AND col_2 > 1;
クエリーにより、以下のデータが返されます。
 key | col_1 | col_2 | col_3 | col_4
-----+-------+-------+-------+-------
 100 |     1 |     2 |     2 |     1
 100 |     1 |     2 |     2 |     2
 100 |     1 |     2 |     2 |     3

(3 rows)

複数のクラスター化セグメントにまたがる範囲を返す

スライス取得を行うと、クラスター化セグメント全体を確認して、複数のカラムの値が一致する行を見つけることができます。スライス・ロジック文は、1つの行の場所を見つけて、その行の前後とその行、およびその間にあるすべての行を返すことができます。

スライスの構文は以下のとおりです。
(clustering1, clustering2[, …]) range_operator (value1, value2[, …]) 
[AND (clustering1, clustering2[, …]) range_operator (value1, value2[, …])]

パーティション全体のスライス

スライスは、ソートされたカラム内の正確な場所を特定します。そのため、行の正確な場所までドリル・ダウンするために、最上位を最初に評価し、次に2番目という順に評価が行われます。次の文は、カラム1、2、3が2に等しく、カラム4が1以下の行を特定するものです。
SELECT * FROM numbers
WHERE key = 100 
AND (col_1, col_2, col_3, col_4) <= (2, 2, 2, 1);

データベースは一致する行を見つけると、特定した行の前にあるすべてのレコードを結果セットで返します。



ヒント: col_1 = 1のとき、col_4の結果には(1より大きい)値2と3が含まれています。カラム4の値はすべてフィルター処理されず、濃い緑色で示されている正確な場所が特定されます。行が見つかると、評価は終了します。
この場所は仮定である場合があり、その場合、値と完全に一致する行はデータセットに含まれません。たとえば、クエリーでスライス値(2, 1, 1, 4)を指定します。
SELECT * FROM numbers
WHERE key = 100 
AND (col_1, col_2, col_3, col_4) <= (2, 1, 1, 4);
クエリーはその値を含む行が存在する場合にその行が現れる順番を見つけて、その前にあるすべての行を返します。

注: カラム4の値は、クラスター化セグメント内の行の配置場所を特定するためにのみ評価されます。データベースはセグメントを特定し、続けてcol_4 = 4を見つけます。場所が見つかると、その行と、ソート順でその行より前にあるすべての行が返されます(この場合はすべてのクラスター化カラムにまたがります)。

クラスター化セグメントのスライス

下位のセグメントでスライスを見つける場合も同じ規則がスライス制約に適用されます。等号またはINを使用して上位のクラスター化セグメントを特定し、下位のセグメントの範囲を指定します。

たとえば、値が(1, 3)よりも大きく、(2, 5)以下である行を返すには、以下のように入力します。
SELECT * FROM numbers  
WHERE key = 100 AND col_1 = 1 AND col_2 = 1 
AND (col_3, col_4) >= (1, 2) 
AND (col_3, col_4) < (2, 3);
間の範囲を見つける場合、階層の最下位カラムについて2つのスライス文が同じカラムを指している必要があります。

無効なクエリー

2つの行の間のスライスを返す場合、スライス文で同じクラスター化カラムを定義する必要があります。カラムが異なるとクエリーは拒否されます。
SELECT * FROM numbers
WHERE key = 100 AND col_1 = 1  
AND (col_2, col_3, col_4) >= (1, 1, 2) 
AND (col_3, col_4) < (2, 3);
InvalidRequest: Error from server: code=2200 [Invalid query] 
message="Column "col_3" cannot be restricted by two inequalities not starting with the same column"

手順

2017年の1月15日から2月14日の間に開始されたロード・サイクリング・レースを見つけます。
eventsの例のテーブルとデータを使用します。
CREATE TABLE cycling.events (
   Year int,
   Start_Month int,
   Start_Day int,
   End_Month int,
   End_Day int,
   Race TEXT,
   Discipline TEXT,
   Location TEXT,
   UCI_code TEXT,
   PRIMARY KEY ((YEAR, Discipline), Start_Month, Start_Day, Race));
スライスを使用して、範囲のstart_monthとstart_dayを制限します。
SELECT start_month as month, start_day as day, race FROM cycling.events 
WHERE year = 2017 AND discipline = 'Road' 
AND (start_month, start_day) < (2, 14) AND (start_month, start_day) > (1, 15);
結果にはその期間中のイベントが含まれています。
 month | day | race
-------+-----+-----------------------------------------------------------------
     1 |  23 |                      Vuelta Ciclista a la Provincia de San Juan
     1 |  26 | Cadel Evans Great Ocean Road Race - Towards Zero Race Melbourne
     1 |  26 | Challenge Mallorca: Trofeo Porreres-Felanitx-Ses Salines-Campos
     1 |  28 |                               Cadel Evans Great Ocean Road Race
     1 |  28 |          Challenge Mallorca: Trofeo Andratx-Mirador des Colomer
     1 |  28 |            Challenge Mallorca: Trofeo Serra de Tramuntana -2017
     1 |  29 |                               Cadel Evans Great Ocean Road Race
     1 |  29 |                             Grand Prix Cycliste la Marseillaise
     1 |  29 |                                Mallorca Challenge: Trofeo Palma
     1 |  31 |                                            Ladies Tour of Qatar
     2 |   1 |                                              Etoile de Besseges
     2 |   1 |                                           Jayco Herald Sun Tour
     2 |   1 |                                 Volta a la Comunitat Valenciana
     2 |   5 |                                       G.P. Costa degli Etruschi
     2 |   6 |                                                   Tour of Qatar
     2 |   9 |                                South African Road Championships
     2 |  11 |                                               Trofeo Laigueglia
     2 |  12 |                                              Clasica de Almeria

(18 rows)