

 Amazon Redshift は、パッチ 198 以降、新しい Python UDF の作成をサポートしなくなります。既存の Python UDF は、2026 年 6 月 30 日まで引き続き機能します。詳細については、[ブログ記事](https://aws.amazon.com/blogs/big-data/amazon-redshift-python-user-defined-functions-will-reach-end-of-support-after-june-30-2026/)を参照してください。

# 自動テーブル最適化
<a name="t_Creating_tables"></a>

自動テーブル最適化は、管理者の介入を必要とせずに、ソートキーとディストリビューションキーを適用することにより、テーブルの設計を自動的に最適化するセルフチューニング機能です。自動化を使用してテーブルの設計を調整することで、テーブルの最適化を手動で調整して実装するために時間を費やすことなく、より簡単に開始し、最速のパフォーマンスをすばやく得ることができます。

自動テーブル最適化は、クエリがテーブルとどのように相互作用するかを継続的に監視します。高度な人工知能メソッドを使用して、ソートキーとディストリビューションキーを選択し、クラスターのワークロードパフォーマンスを最適化します。Amazon Redshift がキーを適用することでクラスターのパフォーマンスが向上すると判断した場合、テーブルは、クラスターが作成されてから数時間以内に自動的に変更され、クエリへの影響は最小限に抑えられます。

この自動化を利用するために、Amazon Redshift 管理者が新しいテーブルを作成するか、既存のテーブルを変更して自動最適化を使用できるようにします。ディストリビューションスタイルまたはソートキーがある `AUTO` の既存のテーブルでは、すでに自動化が有効になっています。これらのテーブルに対してクエリを実行すると、Amazon Redshift はソートキーまたはディストリビューションキーによってパフォーマンスが向上するかどうかを判断します。その場合、Amazon Redshift は管理者の介入を必要とせずにテーブルを自動的に変更します。最小数のクエリが実行されると、クラスターの起動から数時間以内に最適化が適用されます。

 Amazon Redshift が、ディストリビューションキーによってクエリのパフォーマンスが向上すると判断した場合、ディストリビューションスタイルが `AUTO` のテーブルでは、ディストリビューションスタイルを `KEY` に変更できます。

**Topics**
+ [自動テーブル最適化の有効化、無効化、モニタリング](c_ato-enabling-disabling-monitoring.md)
+ [Autonomics から除外するワークロードの管理](t_Manage_workload_exclusion.md)
+ [保存データのサイズを削減するための列圧縮](t_Compressing_data_on_disk.md)
+ [クエリ最適化のためのデータのディストリビューション](t_Distributing_data.md)
+ [ソートキー](t_Sorting_data.md)
+ [テーブルの制約](t_Defining_constraints.md)

# 自動テーブル最適化の有効化、無効化、モニタリング
<a name="c_ato-enabling-disabling-monitoring"></a>

デフォルトでは、ソートキーまたはディストリビューションキーを明示的に定義せずに作成されたテーブルは `AUTO` に設定されています。テーブルの作成時に、ソートキーまたはディストリビューションキーを手動で明示的に設定することもできます。ソートキーまたはディストリビューションキーを設定した場合、テーブルは自動的に管理されません。

## 自動テーブル最適化の有効化
<a name="ato-enabling"></a>

既存のテーブルを自動的に最適化できるようにするには、ALTER ステートメントオプションを使用して、テーブルを `AUTO` に変更します。ソートキーには自動化を定義できますが、ディストリビューションキーには自動化を定義することができません (逆も同様)。ALTER ステートメントを実行してテーブルを自動テーブルに変換する場合、既存のソートキーとディストリビューションスタイルは保持されます。

```
ALTER TABLE table_name ALTER SORTKEY AUTO;
```

```
ALTER TABLE table_name ALTER DISTSTYLE AUTO;
```

詳細については、「[ALTER TABLE](r_ALTER_TABLE.md)」を参照してください。

最初は、テーブルにはディストリビューションキーまたはソートキーがありません。ディストリビューションスタイルは、テーブルのサイズに応じて `EVEN` または `ALL` のいずれかに設定されます。テーブルのサイズが大きくなるにつれて、Amazon Redshift は最適なディストリビューションキーとソートキーを適用します。最適化は、最小数のクエリが実行されてから数時間以内に適用されます。ソートキーの最適化を決定するとき、Amazon Redshift はテーブルスキャン中にディスクから読み込んだデータブロックを最適化しようとします。ディストリビューションスタイルの最適化を決定するとき、Amazon Redshift はクラスターノード間で転送されるバイト数を最適化しようとします。

## テーブルからの自動テーブル最適化の削除
<a name="ato-disabling"></a>

自動最適化からテーブルを削除できます。オートメーションからテーブルを削除するには、ソートキーまたはディストリビューションスタイルを選択します。ディストリビューションスタイルを変更するには、特定のディストリビューションスタイルを指定します。

```
ALTER TABLE table_name ALTER DISTSTYLE EVEN;
```

```
ALTER TABLE table_name ALTER DISTSTYLE ALL;
```

```
ALTER TABLE table_name ALTER DISTSTYLE KEY DISTKEY c1;
```

ソートキーを変更するには、ソートキーを定義するか、[none (なし)] を選択します。

```
ALTER TABLE table_name ALTER SORTKEY(c1, c2);
```

```
ALTER TABLE table_name ALTER SORTKEY NONE;
```

## 自動テーブル最適化のモニタリング
<a name="ato-monitoring-actions"></a>

システムビュー `SVV_ALTER_TABLE_RECOMMENDATIONS` は、テーブルに対する現在の Amazon Redshift Advisor のレコメンデーションを記録します。このビューには、自動最適化用に定義されているテーブルと定義されていないテーブルのすべてのレコメンデーションが表示されます。

テーブルが自動最適化用に定義されているかどうかを表示するには、システムビュー `SVV_TABLE_INFO` にクエリを実行します。エントリは、現在のセッションのデータベースに表示されているテーブルに対してのみ表示されます。レコメンデーションは、クラスターの作成時刻から数時間以内に開始され、1 日に 2 回ビューに挿入されます。レコメンデーションが利用可能になると、1 時間以内に開始されます。(Amazon Redshift またはユーザーのいずれかによって) レコメンデーションが適用されると、ビューに表示されなくなります。

システムビュー `SVL_AUTO_WORKER_ACTION` には、Amazon Redshift によって実行されたすべてのアクションに関する監査ログとテーブルの以前の状態が表示されます。

システムビュー `SVV_TABLE_INFO` には、システム内のすべてのテーブルが、テーブルのソートキーとディストリビューションスタイルが `AUTO` に設定されているかどうかを示す列とともに一覧表示されます。

これらのシステムビューの詳細については、[システムモニタリング (プロビジョニングのみ)](c_intro_system_views.md) を参照してください。

# Autonomics から除外するワークロードの管理
<a name="t_Manage_workload_exclusion"></a>

 拒否リスト機能を使用して、特定のプロビジョニングされたエンドポイントやサーバーレスワークグループが、ディストリビューションキーやソートキーなどの自律的な決定に影響を与える動作を除外できます。これにより、Amazon Redshift が Redshift マネージドストレージ (RMS) データの最適化を決定する際に考慮するワークロードを制御できます。

 **拒否リストの使用** 

 Amazon Redshift コンソールの [Autonomics] セクションから拒否リストを管理できます。

1.  **項目の追加または削除** 

    特定のプロビジョニングされたエンドポイントまたはサーバーレスワークグループを拒否リストに追加し、必要に応じて削除します。

1.  **表示と検索** 

   拒否リストのすべての項目を表示し、拒否リスト内の特定のエンドポイントまたはワークグループを検索します。

 拒否リストは、データマーケットプレイスを実行したり、外部ユーザーとデータを共有したり、複数のビジネスユニットがあり、特定の使用パターンがワークロードに適した最適化の決定に影響を与えないようにしたりする場合に特に便利です。例えば、ワークグループ A がワークロード A を実行し、ワークグループ B が共有テーブル T でワークロード B を実行する場合、T のソートキーはワークロード A と B の両方によって決定されます。ワークロード A のみがソートキーの決定に影響を与えるようにする場合は、テーブル T を所有するエンドポイントかワークグループの拒否リストにワークグループ B を追加します。Amazon Redshift Autonomics は拒否リストで特に除外されない限り、デフォルトでは、プロデューサーとすべてのコンシューマークラスター/ワークグループからのクエリパターンを考慮します。

**注記**  
 同じアカウント内の異なる AWS リージョン間でリソースを拒否リストに登録できます。クロスアカウント拒否リストはまだサポートされていません。

## Amazon Redshift コンソールでの拒否リストリソースの管理
<a name="manage-denylist-console"></a>

Amazon Redshift Serverless コンソールで、以下の手順を完了します。

1. クラスターまたはサーバーレスワークグループを選択します。

1. 特定のクラスターまたはワークグループの詳細ページに移動します。

1. タブセクションで [Autonomics] を選択します。

1. [Autonomics] タブで、拒否リストを表示および管理できます。

1. クロスリージョン拒否リストを管理するには、対応する AWS リージョンを選択します。

## 拒否リストにリソースを追加する
<a name="add-denylist"></a>

1. 選択したクラスターまたはワークグループの [Autonomics] タブに移動し、AWS リージョンを選択し、[リソースを追加] を選択します。

1.  拒否リストに追加する 1 つ以上のプロビジョニングされたクラスターまたはサーバーレスワークグループを選択し、[追加] を選択します。

1. この表は、拒否リストリソースのリストを示しています。

## 拒否リストのリソースを削除する
<a name="remove-denylist"></a>

1. 選択したクラスターまたはワークグループの [Autonomics] タブに移動し、AWS リージョンを選択します。

1. リストから削除するクラスターまたはワークグループを選択し、[削除] を選択します。

1. 確認ダイアログボックスが開きます。[削除] をクリックして確定します。

# 保存データのサイズを削減するための列圧縮
<a name="t_Compressing_data_on_disk"></a>

*圧縮*は、データの保存時にそのサイズを小さくする列レベルのオペレーションです。圧縮によってストレージスペースが節約され、ストレージから読み込まれるデータのサイズが小さくなり、ディスク I/O の量が減少するので、クエリパフォーマンスが向上します。

ENCODE AUTO は、テーブルのデフォルトです。テーブルが ENCODE AUTO に設定されると、Amazon Redshift は、テーブル内のすべての列の圧縮エンコードを自動的に管理します。詳細については、「[CREATE TABLE](r_CREATE_TABLE_NEW.md)」および「[ALTER TABLE](r_ALTER_TABLE.md)」を参照してください。

ただし、テーブル内のいずれかの列に圧縮エンコードを指定すると、テーブルは ENCODE AUTO に設定されなくなります。Amazon Redshift は、テーブルにあるすべての列の圧縮エンコードを自動的に管理しないようになりました。

テーブルを作成するときに、テーブルの列に圧縮タイプまたは*エンコード*を手動で適用できます。または、COPY コマンドを使用すると、自動的に圧縮を分析および適用できます。詳細については、「[COPY による圧縮エンコードの選択](c_best-practices-use-auto-compression.md)」を参照してください。自動圧縮の適用の詳細については、「[自動圧縮ありでテーブルをロードする](c_Loading_tables_auto_compress.md)」を参照してください。

**注記**  
COPY コマンドを使用して自動圧縮を適用することを強くお勧めします。

新しいテーブルが別のテーブルと同じデータ特性を共有している場合は、圧縮エンコードを手動で適用することを選択できます。または、自動圧縮時に適用される圧縮エンコードがデータにとって最適ではないことがテストで判明した場合は、ユーザーが管理することもできます。圧縮エンコードを手動で適用する場合は、すでに入力されているテーブルに対して [ANALYZE COMPRESSION](r_ANALYZE_COMPRESSION.md) コマンドを再実行し、その結果を使用して圧縮エンコードを選択することができます。

圧縮を手動で適用するには、CREATE TABLE ステートメントの一部として個々の列に対して圧縮エンコードを指定します。構文は次のとおりです。

```
CREATE TABLE table_name (column_name 
data_type ENCODE encoding-type)[, ...]
```

ここで、*encoding-type* には次のセクションのキーワード表から選択します。

例えば、次のステートメントは 2 列のテーブル PRODUCT を作成します。データがテーブルにロードされるときに、PRODUCT\$1ID 列は圧縮されませんが、PRODUCT\$1NAME 列はバイトディクショナリエンコード (BYTEDICT) を使用して圧縮されます。

```
create table product(
product_id int encode raw,
product_name char(20) encode bytedict);
```

ALTER TABLE コマンドを使用して列をテーブルに追加する際には、列のエンコードを指定できます。

```
ALTER TABLE table-name ADD [ COLUMN ] column_name column_type ENCODE encoding-type
```

**Topics**
+ [圧縮エンコード](c_Compression_encodings.md)
+ [圧縮エンコードのテスト](t_Verifying_data_compression.md)

# 圧縮エンコード
<a name="c_Compression_encodings"></a>

<a name="compression-encoding-list"></a>*圧縮エンコード*は、行がテーブルに追加されるときにデータ値の列に適用される圧縮のタイプを指定します。

ENCODE AUTO は、テーブルのデフォルトです。テーブルが ENCODE AUTO に設定されると、Amazon Redshift は、テーブル内のすべての列の圧縮エンコードを自動的に管理します。詳細については、「[CREATE TABLE](r_CREATE_TABLE_NEW.md)」および「[ALTER TABLE](r_ALTER_TABLE.md)」を参照してください。

ただし、テーブル内のいずれかの列に圧縮エンコードを指定すると、テーブルは ENCODE AUTO に設定されなくなります。Amazon Redshift は、テーブルにあるすべての列の圧縮エンコードを自動的に管理しないようになりました。

CREATE TABLE を使用すると、テーブル内の列の圧縮エンコードを指定するとき、ENCODE AUTO は無効です。ENCODE AUTO が無効なとき、Amazon Redshift は、ユーザーが ENCODE タイプを指定していない列について、次のように圧縮エンコードを自動的に割り当てます。
+ ソートキーとして定義されている列には、RAW 圧縮が割り当てられます。
+ BOOLEAN、REAL、または DOUBLE PRECISION データ型として定義されている列には、RAW 圧縮が割り当てられます。
+ SMALLINT、INTEGER、BIGINT、DECIMAL、DATE、TIMESTAMP、または TIMESTAMPTZ データ型として定義された列には AZ64 圧縮が割り当てられます。
+ CHAR または VARCHAR データ型として定義された列には、LZO 圧縮が割り当てられます。

テーブルのエンコードは、作成後に ALTER TABLE を使用して変更できます。ALTER TABLE を使用して ENCODE AUTO を無効にした場合、Amazon Redshift は列の圧縮エンコードを自動的に管理しなくなります。すべての列の圧縮エンコードタイプは、ユーザーが変更するか、ENCODE AUTO を再び有効にするまで、ENCODE AUTO を無効にしたときの圧縮エンコードタイプのままです。

Amazon Redshift は、以下の圧縮エンコーディングをサポートしています。

------
#### [ Raw ]

Raw エンコードは、ソートキー、および BOOLEAN、REAL、または DOUBLE PRECISION データ型として定義された列として指定された列のエンコードのデフォルトです。raw エンコードでは、データは非圧縮の raw 形式で格納されます。

------
#### [ AZ64 ]

AZ64 は、高い圧縮率とクエリ処理能力の改善を実現するために Amazon によって設計された独自の圧縮エンコードアルゴリズムです。Z64 アルゴリズムは、より小さなデータ値のグループを圧縮し、並列処理に SIMD (Single Instruction Multiple Data) 命令を使用します。AZ64 を使用すると、数値、日付、および時刻データ型のストレージを大幅に節約し、高いパフォーマンスを実現できます。

次のデータ型の CREATE TABLE および ALTER TABLE ステートメントを使用して列を定義する場合、AZ64 を圧縮エンコードとして使用できます。
+ SMALLINT
+ INTEGER
+ BIGINT
+ DECIMAL
+ DATE
+ TIMESTAMP
+ TIMESTAMPTZ

------
#### [ Byte-dictionary ]

バイトディクショナリエンコードでは、ディスク上の列値のブロックごとに、一意の値の個別のディクショナリが作成されます (Amazon Redshift のディスクブロックは 1 MB を占有します。) ディクショナリには、元のデータ値のインデックスとして格納されている最大 256 個の 1 バイト値が含まれます。単一のブロックに 256 個を超える値が格納されている場合は、余分な値が非圧縮の raw 形式でブロックに書き込まれます。ディスクブロックごとに、このプロセスが繰り返されます。

このエンコードは、低カーディナリティ文字列の列に対して非常に効果的です。このエンコードは、列のデータドメインが一意の値 256 個未満である場合に最適です。

BYTEDICT でエンコードされた文字列データ型 (CHAR と VARCHAR) の列の場合、Amazon Redshift は圧縮されたデータを直接処理するベクタースキャンと述語評価を実行します。これらのスキャンでは、ハードウェア固有の単一命令複数データ (SIMD) 命令が使用されて、並列処理が行われます。これにより、文字列列のスキャンが大幅に加速されます。バイトディクショナリエンコードは、CHAR/VARCHAR 列に長い文字列が含まれる場合に特にスペース効率が高まります。

テーブルに、CHAR(30) データ型の COUNTRY 列があるとします。データがロードされると、Amazon Redshift はディクショナリを作成し、COUNTRY 列にインデックス値を入力します。ディクショナリには、インデックス作成された一意の値が含まれ、テーブル自体には、対応する値の 1 バイトのサブスクリプトのみが含まれます。

**注記**  
固定長文字の列には末尾の空白が格納されます。したがって CHAR(30) 列では、バイトディクショナリエンコードを使用すると、圧縮値ごとに 29 バイトのストレージが節約されます。

次の表は、COUNTRY 列のディクショナリを示しています。

[\[See the AWS documentation website for more details\]](http://docs.aws.amazon.com/ja_jp/redshift/latest/dg/c_Compression_encodings.html)

次の表は、COUNTRY 列の値を示しています。

[\[See the AWS documentation website for more details\]](http://docs.aws.amazon.com/ja_jp/redshift/latest/dg/c_Compression_encodings.html)

この例の合計圧縮サイズは、次のように計算されます。ディクショナリに 6 つの異なるエントリが格納され (6 \$1 30 = 180)、テーブルに 10 個の 1 バイト圧縮値が含まれて、合計 190 バイトとなります。

------
#### [ Delta ]

デルタエンコードは、日時列にとって非常に有用です。

デルタエンコードは、列内の連続する値間の差を記録することにより、データを圧縮します。この差は、ディスク上の列値の各ブロックに対する個別のディクショナリに記録されます (Amazon Redshift のディスクブロックは 1 MB を占有します。) 例えば、列に 1 から 10 までの 10 個の整数が順番に含まれているとします。最初の値は 4 バイトの整数 (\$1 1 バイトのフラグ) として保存されます。次の 9 つはそれぞれ値 1 のバイトとして保存され、前の値より 1 大きいことを示します。

デルタエンコードには、次の 2 つのバージョンがあります。
+ 差を 1 バイト値 (8 ビット整数) として記録する DELTA
+ 差を 2 バイト値 (16 ビット整数) として記録する DELTA32K

1 バイトを使用して列内のほとんどの値を圧縮できる場合は、1 バイトの変形が非常に効果的です。しかし、最悪の場合、デルタがより大きいと、このエンコードは非圧縮データを保存する場合よりも多少効果が低くなる可能性もあります。16 ビットバージョンにも同様の論理が当てはまります。

2 つの値間の差が 1 バイトの範囲 (DELTA) または 2 バイトの範囲 (DELTA32K) を超える場合は、先頭に 1 バイトのフラグが付けられて元の完全な値が格納されます。1 バイトの範囲は -127～127、2 バイトの範囲は -32K～32K です。

次の表は、デルタエンコードが数値列に対してどのように機能するかを示しています。

[\[See the AWS documentation website for more details\]](http://docs.aws.amazon.com/ja_jp/redshift/latest/dg/c_Compression_encodings.html)

------
#### [ LZO ]

LZO エンコードは、非常に高い圧縮率と良好なパフォーマンスを実現します。LZO エンコードは、非常に長い文字列を格納する CHAR 列および VARCHAR 列に対して使用すると特に効果的です。製品説明、ユーザーコメント、JSON 文字列などの自由形式テキストに適しています。

------
#### [ Mostly ]

Mostly エンコードは、列のデータ型が、格納された大部分の値で必要なサイズより大きい場合に有用です。このタイプの列に Mostly エンコードを指定して、列内の大部分の値を、より小さい標準ストレージサイズに圧縮することができます。圧縮できない残りの値は、raw 形式で格納されます。例えば、INT2 列などの 16 ビット列を 8 ビットストレージに圧縮できます。

一般的に、Mostly エンコードは次のデータ型に対して使用します。
+ SMALLINT/INT2 (16 ビット)
+ INTEGER/INT (32 ビット)
+ BIGINT/INT8 (64 ビット)
+ DECIMAL/NUMERIC (64 ビット)

列のデータ型のサイズに見合う Mostly エンコードの適切なバージョンを選択します。例えば、16 ビット整数列として定義された列に MOSTLY8 を適用します。MOSTLY16 を 16 ビットデータ型の列に適用したり、MOSTLY32 を 32 ビットデータ型の列に適用したりすることはできません。

列内の比較的多くの値を圧縮できない場合、Mostly エンコードは非圧縮の場合よりも効果が低くなります。これらのエンコードの 1 つを列に適用する前に、確認してください。現在ロードしようとしている (そして今後ロードする可能性が高い) 値の*ほとんど*は、次のテーブルに示す範囲に収まるはずです。

[\[See the AWS documentation website for more details\]](http://docs.aws.amazon.com/ja_jp/redshift/latest/dg/c_Compression_encodings.html)

**注記**  
10 進値では、値が範囲内にあるかどうかを判断する場合に小数点を無視します。例えば、1,234.56 は 123,456 として扱われ、MOSTLY32 列で圧縮できます。

例えば、VENUE テーブルの VENUEID 列が raw 整数列として定義されている場合は、その値が 4 バイトのストレージを消費することを意味します。しかし、列の値の現在の範囲は **0**～**309** です。したがって、VENUEID に対して MOSTLY16 エンコードを使用してこのテーブルを再作成および再ロードすると、その列の各値のストレージが 2 バイトに減少します。

別のテーブルで参照される VENUEID 値のほとんどが 0～127 の範囲内にある場合、その外部キー列を MOSTLY8 としてエンコードすることは妥当と言えます。選択を行う前に、参照テーブルデータに対していくつかのクエリを実行して、ほとんどの値が 8 ビット、16 ビット、または 32 ビットの範囲内にあるかどうかを確認する必要があります。

次の表は、MOSTLY8、MOSTLY16、および MOSTLY32 エンコードが使用される場合の特定の数値の圧縮サイズを示しています。

[\[See the AWS documentation website for more details\]](http://docs.aws.amazon.com/ja_jp/redshift/latest/dg/c_Compression_encodings.html)

------
#### [ Run length ]

ランレングスエンコードは、連続して繰り返される値を、値と連続発生数 (実行の長さ) から成るトークンに置き換えます。ディスク上の列値のブロックごとに、一意の値の個別のディクショナリが作成されます (Amazon Redshift のディスクブロックは 1 MB を占有します。) このエンコードは、データ値が連続して頻繁に繰り返されるテーブル (例えば、テーブルがこれらの値でソートされる場合) に最も適しています。

例えば、大きなディメンションテーブルの列に、予測どおりに小さなドメイン (10 個未満の可能な値を持つ COLOR 列など) があるとします。これらの値は、データがソートされていない場合でも、テーブル全体で長いシーケンスに分類される可能性があります。

ソートキーとして指定された列に、ランレングスエンコードを適用することは推奨されません。範囲が制限されたスキャンは、ブロックに同様の数の行が含まれる場合にパフォーマンスが向上します。ソートキー列が、同じクエリ内の他の列よりもかなり高度に圧縮される場合、範囲が制限されたスキャンはパフォーマンスが低下する可能性があります。

次の表は、COLOR 列の例を使用して、ランレングスエンコードがどのように機能するかを示しています。

[\[See the AWS documentation website for more details\]](http://docs.aws.amazon.com/ja_jp/redshift/latest/dg/c_Compression_encodings.html)

------
#### [ Text255 and Text32k ]

text255 および text32k エンコードは、同じ単語が頻繁に出現する VARCHAR 列を圧縮する場合に有用です。ディスク上の列値のブロックごとに、一意の単語の個別のディクショナリが作成されます (Amazon Redshift のディスクブロックは 1 MB を占有します。) ディクショナリには、列内の最初の 245 個の一意の単語が含まれます。これらの単語は、ディスク上で、245 個の値の 1 つを表す 1 バイトインデックス値に置き換えられ、ディクショナリに表されていないすべての単語は非圧縮で格納されます。このプロセスは、1 MB のディスクブロックごとに繰り返されます。インデックス作成された単語が列内に頻繁に出現する場合、列の圧縮率は非常に高くなります。

text32k エンコードでも原理は同じですが、各ブロックのディクショナリは特定数の単語をキャプチャすることはありません。代わりにディクショナリは、結合されたエントリが、32K から多少のオーバーヘッドを減算した長さに達するまで、検出した一意の各単語のインデックスを作成します。インデックス値は 2 バイトで格納されます。

例えば、VENUE テーブルの VENUENAME 列を考えてみます。この列には **Arena**、**Center**、**Theatre** などの単語が繰り返し出現し、text255 圧縮が適用された場合、各ブロックに出現する最初の 245 個の単語内にこれらが含まれると考えられます。その場合、この列は圧縮の利点を利用できます。その場合、これらの単語が出現するたびに 1 バイトのストレージ (それぞれ 5、6、または 7 バイトではなく) を占めるにすぎないのが理由です。

------
#### [ ZSTD ]

Zstandard (ZSTD) エンコードは、多様なデータセット間で非常にパフォーマンスのいい高圧縮比率を提供します。ZSTD は、製品説明、ユーザーのコメント、ログ、JSON 文字列など、長さがさまざまな文字列を保存する CHAR および VARCHAR 列に対して、特に効果を発揮します。一部のアルゴリズム (デルタエンコードや Mostly エンコードなど) では非圧縮時よりもストレージスペースの使用量が増える場合がありますが、ZSTD ではディスク使用量が増えることはありません。

ZSTD は、SMALLINT、INTEGER、BIGINT、DECIMAL、REAL、DOUBLE PRECISION、BOOLEAN、CHAR、VARCHAR、DATE、TIMESTAMP、および TIMESTAMPTZ データ型をサポートします。

------

次の表は、サポートされる圧縮エンコード、およびエンコードをサポートするデータ型を示しています。

[\[See the AWS documentation website for more details\]](http://docs.aws.amazon.com/ja_jp/redshift/latest/dg/c_Compression_encodings.html)

# 圧縮エンコードのテスト
<a name="t_Verifying_data_compression"></a>

列のエンコードを手動で指定する場合は、データに対してさまざまなエンコードをテストできます。

**注記**  
できる限り COPY コマンドを使用してデータをロードし、データに基づいて最適なエンコードを COPY コマンドが選択できるようにすることをお勧めします。または、[ANALYZE COMPRESSION](r_ANALYZE_COMPRESSION.md) コマンドを使用して、既存のデータに対して提案されるエンコードを表示できます。自動圧縮の適用の詳細については、「[自動圧縮ありでテーブルをロードする](c_Loading_tables_auto_compress.md)」を参照してください。

データ圧縮の有意義なテストを実行するには、多数の行が必要になります。この例では、2 つのテーブル VENUE と LISTING から選択を行うステートメントを使用して、テーブルを作成し行を挿入します。通常は 2 つのテーブルを結合する WHERE 句は省略します。その結果、VENUE テーブルの*各*行が LISTING テーブルの*すべての*行に結合されて、合計 3200 万以上の行になります。これはデカルト結合と呼ばれ、通常はお勧めしません。ただし、この目的においては、多数の行を作成する便利な方法です。テストするデータを含む既存のテーブルがある場合は、このステップをスキップできます。

サンプルデータを含むテーブルを作成したら、7 列のテーブルを作成します。それぞれ異なる圧縮エンコード (raw、bytedict、lzo、run length、text255、text32k、および zstd) が適用されます。最初のテーブルからデータを選択する INSERT コマンドを実行することにより、各列に全く同じデータを入力します。

圧縮エンコードをテストするには、以下を実行します。

1.  (オプション) 最初に、デカルト結合を使用して、多数の行を含むテーブルを作成します。既存のテーブルをテストする場合は、このステップをスキップします。

   ```
   create table cartesian_venue(
   venueid smallint not null distkey sortkey,
   venuename varchar(100),
   venuecity varchar(30),
   venuestate char(2),
   venueseats integer);
   
   insert into cartesian_venue
   select venueid, venuename, venuecity, venuestate, venueseats
   from venue, listing;
   ```

1.  次に、比較する各エンコードを含むテーブルを作成します。

   ```
   create table encodingvenue (
   venueraw varchar(100) encode raw,
   venuebytedict varchar(100) encode bytedict,
   venuelzo varchar(100) encode lzo,
   venuerunlength varchar(100) encode runlength,
   venuetext255 varchar(100) encode text255,
   venuetext32k varchar(100) encode text32k,
   venuezstd varchar(100) encode zstd);
   ```

1.  INSERT ステートメントを SELECT 句とともに使用して、すべての列に同じデータを挿入します。

   ```
   insert into encodingvenue
   select venuename as venueraw, venuename as venuebytedict, venuename as venuelzo, venuename as venuerunlength, venuename as  venuetext32k, venuename as  venuetext255, venuename as venuezstd
   from cartesian_venue;
   ```

1.  新しいテーブルの行数を確認します。

   ```
   select count(*) from encodingvenue
   
     count
   ----------
    38884394
   (1 row)
   ```

1.  [STV\$1BLOCKLIST](r_STV_BLOCKLIST.md) システムテーブルをクエリ処理して、各列で使用される 1 MB のディスクブロックの数と比較します。

   MAX 集計関数が、各列のブロックの最高数を返します。STV\$1BLOCKLIST テーブルには、3 つのシステム生成列の詳細が含まれます。この例では、WHERE 句で `col < 6` を使用して、システム生成列を除外します。

   ```
   select col, max(blocknum)
   from stv_blocklist b, stv_tbl_perm p
   where (b.tbl=p.id) and name ='encodingvenue'
   and col < 7
   group by name, col
   order by col;
   ```

   クエリは次の結果を返します。列には 0 から始まる番号が付けられています。クラスターの設定方法によっては結果の数が異なる場合がありますが、相対的なサイズは同様のものになります。このデータセットについては、2 列目の BYTEDICT エンコードから、最良の結果が得られました。このアプローチの圧縮比は 20:1 よりも優れています。LZO および ZSTD エンコードからも良好な結果が得られました。もちろん、異なるデータセットからは異なる結果が得られます。より長い文字列が列に含まれる場合は、LZO から最良の圧縮結果が得られることが多くなります。

   ```
    col | max
   -----+-----
      0 | 203
      1 |  10
      2 |  22
      3 | 204
      4 |  56
      5 |  72
      6 |  20
   (7 rows)
   ```

既存のテーブルにデータが存在する場合は、[ANALYZE COMPRESSION](r_ANALYZE_COMPRESSION.md) コマンドを使用して、テーブルに対して提案されるエンコードを表示できます。例えば、次の例は、3800 万行を含む VENUE テーブル CARTESIAN\$1VENUE のコピーに対して推奨されるエンコードを示しています。ANALYZE COMPRESSION により VENUENAME 列には LZO エンコードが推奨されています。ANALYZE COMPRESSION は減少率を含む複数の要素に基づいて最適な圧縮を選択します。この特定のケースでは、BYTEDICT の方がより圧縮できますが、LZO でも 90 パーセントを超える圧縮になります。

```
analyze compression cartesian_venue;

Table          | Column     | Encoding | Est_reduction_pct
---------------+------------+----------+------------------
reallybigvenue | venueid    | lzo      | 97.54            
reallybigvenue | venuename  | lzo      | 91.71            
reallybigvenue | venuecity  | lzo      | 96.01            
reallybigvenue | venuestate | lzo      | 97.68            
reallybigvenue | venueseats | lzo      | 98.21
```

## 例
<a name="Examples__compression_encodings_in_CREATE_TABLE_statements"></a>

次の例は、さまざまなデータ型の列を含む CUSTOMER テーブルを作成します。この CREATE TABLE ステートメントは、これらの列に対する圧縮エンコードの数ある可能な組み合わせの 1 つを示しています。

```
create table customer(
custkey int encode delta,
custname varchar(30) encode raw,
gender varchar(7) encode text255,
address varchar(200) encode text255,
city varchar(30) encode text255,
state char(2) encode raw,
zipcode char(5) encode bytedict,
start_date date encode delta32k);
```

次の表は、CUSTOMER テーブルに対して選択された列エンコードを示し、それぞれの選択内容について説明しています。


| 列 | データ型 | エンコード | 説明 | 
| --- | --- | --- | --- | 
| CUSTKEY | int | delta | CUSTKEY は、連続した一意の整数値から成ります。差は 1 バイトとなるので、DELTA を選択するのが適切です。 | 
| CUSTNAME | varCHAR(30) | raw | CUSTNAME には、繰り返し値がほとんどない大きなドメインがあります。いずれの圧縮エンコードも効果的でないと考えられます。 | 
| GENDER | varchar(7) | text255 | GENDER は、多数の繰り返し値を含む非常に小さなドメインです。同じ単語が繰り返し出現する VARCHAR 列には、text255 が適しています。 | 
| ADDRESS | varchar(200) | text255 | ADDRESS は大きなドメインですが、Street、Avenue、North、South など、繰り返しの単語が多数含まれます。同じ単語が繰り返し出現する VARCHAR 列を圧縮するには、text255 と text32k が有用です。列が短いので、text255 を選択するのが適切です。 | 
| CITY | varCHAR(30) | text255 | CITY は、いくつかの繰り返し値を含む大きなドメインです。特定の市の名前が、他の市の名前よりもかなり頻繁に使用されます。ADDRESS と同じ理由により、text255 を選択するのが適切です。 | 
| STATE | char(2) | raw | 米国では、STATE は 50 個の 2 文字値の正確なドメインです。bytedict エンコードによって多少圧縮されるものの、列サイズが 2 文字のみであるため、データの解凍時のオーバーヘッドを考慮すると圧縮する必要はそれほどないと考えられます。 | 
| ZIPCODE | char(5) | bytedict | ZIPCODE は、50,000 個未満の一意の値を含む既知のドメインです。特定の郵便番号が、他の郵便番号よりもかなり頻繁に出現します。bytedict エンコードは、数に制限のある一意の値が列に含まれる場合に非常に効果的です。 | 
| START\$1DATE | date | delta32k | デルタエンコードは、特に行が日付順にロードされる場合に、日時列にとって非常に有用です。 | 

# クエリ最適化のためのデータのディストリビューション
<a name="t_Distributing_data"></a>

テーブルにデータをロードすると、そのテーブルの分散スタイルに従って、Amazon Redshift がテーブルの行を各コンピューティングノードに分散します。クエリを実行すると、必要に応じて結合と集計を実行するために、クエリオプティマイザによって行がコンピューティングノードに再分散されます。テーブル分散スタイルの選択は、クエリを実行する前にデータを必要な場所に配置しておくことによって、再分散ステップの影響を最小限に抑えるために行われます。

**注記**  
このセクションでは、Amazon Redshift データベースにおけるデータディストリビューションの原則について説明します。`DISTSTYLE AUTO` を使用してテーブルを作成することをお勧めします。その場合、Amazon Redshift は自動テーブル最適化を使用してデータディストリビューションスタイルを選択します。詳細については、「[自動テーブル最適化](t_Creating_tables.md)」を参照してください。このセクションの残りの部分では、ディストリビューションスタイルについて詳しく説明します。

**Topics**
+ [データ分散の概念](#t_data_distribution_concepts)
+ [分散スタイル](c_choosing_dist_sort.md)
+ [分散スタイルの表示](viewing-distribution-styles.md)
+ [クエリパターンの評価](t_evaluating_query_patterns.md)
+ [分散スタイルの指定](t_designating_distribution_styles.md)
+ [クエリプランの評価](c_data_redistribution.md)
+ [クエリプランの例](t_explain_plan_example.md)
+ [分散の例](c_Distribution_examples.md)

## データ分散の概念
<a name="t_data_distribution_concepts"></a>

以下に、Amazon Redshift のデータディストリビューションの概念をいくつか示します。

 **ノードとスライス** 

 Amazon Redshift クラスターは一連のノードです。クラスター内の各ノードには、独自のオペレーティングシステム、専用メモリ、および専用のディスクストレージが備わっています。ノードの 1 つは*リーダーノード*であり、コンピューティングノードへのデータの分散およびクエリ処理タスクを管理します。*コンピューティングノード*は、これらのタスクを実行するためのリソースを提供します。

 コンピューティングノードのディスクストレージは複数のスライスに*分割*されています。ノードあたりのスライスの数は、クラスターのノードサイズによって決まります。ノードはいずれも並列クエリの実行に関与し、スライス全体でできるだけ均等に分散されたデータを処理します。各ノードサイズに含まれるスライスの数の詳細については、「*Amazon Redshift 管理ガイド*」の「[クラスターおよびノードについて](https://docs.aws.amazon.com/redshift/latest/mgmt/working-with-clusters.html#rs-about-clusters-and-nodes)」を参照してください。

 **データの再分散** 

 テーブルにデータをロードすると、そのテーブルの分散スタイルに従って、Amazon Redshift がテーブルの行を各ノードスライスに分散します。クエリプランの一環として、クエリオプティマイザは、クエリの実行を最適化するために必要なデータブロックの配置場所を決定します。クエリの実行中にデータが物理的に移動または再配信されます。再分散では、結合する特定の行を送信するか、またはテーブル全体をすべてのノードにブロードキャストすることが必要となる場合があります。

 データの再分散は、クエリプランコストの相当な部分を占める可能性があり、また、再分散によって生成されるネットワークトラフィックは、他のデータベース処理に影響を及ぼし、システム全体のパフォーマンスを低速化する可能性があります。データを最初にどこに配置すれば最も効果的かを予測すると、データ再分散の影響を最小限に抑えることができます。

 **データ分散の目標** 

 テーブルにデータをロードすると、そのテーブルを作成したときに選択した分散スタイルに従って、Amazon Redshift がテーブルの行をコンピューティングノードとスライスに分散します。データ分散では、次の 2 つの主要目標が設定されます。
+ クラスター内のノード間でワークロードを均等に分散させること。不均等な分散が行われると (データ分散スキュー)、一部のノードの作業量が他のノードよりも多くなり、クエリのパフォーマンスが低下します。
+ クエリの実行中にデータ移動を最小限に抑えるため。結合または集計に関与する行が、他のテーブルの結合列とともにノード上ですでにコロケーションされている場合、クエリ実行中に再分散する必要のあるデータの量はそれほど多くなりません。

データベースにどの分散戦略を選択するかは、クエリのパフォーマンス、ストレージ要件、データロード、およびメンテナンスに重大な影響を及ぼします。各テーブルに最良の分散スタイルを選択することにより、データを均等に分散し、システム全体のパフォーマンスを大幅に向上させることができます。

# 分散スタイル
<a name="c_choosing_dist_sort"></a>

テーブルを作成する場合は、以下の AUTO、EVEN、KEY、または ALL という分散スタイルのいずれかを指定します。

分散スタイルを指定しない場合、Amazon Redshift は AUTO 分散を使用します。

 **AUTO 分散** 

AUTO 分散では、Amazon Redshift はテーブルデータのサイズに基づいて最適な分散スタイルを割り当てます。例えば、AUTO 分散スタイルが指定された場合、Amazon Redshift ではまず、ALL 分散スタイルを小さなテーブルに割り当てます。テーブルが大きくなると、Amazon Redshift は分散スタイルを KEY に変更し、プライマリキー (または複合プライマリキーの列) を分散キーとして選択する場合があります。テーブルが大きくなり、分散キーに適した列がない場合、Amazon Redshift は分散スタイルを EVEN に変更します。ディストリビューションスタイルの変更は、ユーザークエリへの影響を最小限に抑え、バックグラウンドで発生します。

テーブルのディストリビューションキーを変更するために Amazon Redshift が自動的に実行したアクションを表示するには、[SVL\$1AUTO\$1WORKER\$1ACTION](r_SVL_AUTO_WORKER_ACTION.md) を参照してください。テーブルのディストリビューションキーの変更に関する現在の推奨事項を表示するには、[SVV\$1ALTER\$1TABLE\$1RECOMMENDATIONS](r_SVV_ALTER_TABLE_RECOMMENDATIONS.md) を参照してください。

テーブルに適用された分散スタイルを表示するには、PG\$1CLASS\$1INFO システムカタログビューに対してクエリを実行します。詳細については、「[分散スタイルの表示](viewing-distribution-styles.md)」を参照してください。CREATE TABLE ステートメントで分散スタイルを指定しない場合、Amazon Redshift は AUTO 分散を適用します。

 **EVEN 分散** 

 リーダーノードは、特定の列の値に含まれている値にかかわらず、ラウンドロビン方式によって複数のスライス間で行を分散させます。テーブルが結合に参加しない場合は、EVEN ディストリビューションが適切です。KEY ディストリビューションと ALL ディストリビューションのどちらかを明確に選択できない場合にも適しています。

 **キー分散** 

 行の分散は、特定の列に含まれている値に従って行われます。リーダーノードは、複数の一致する値を同じノードスライスに配置します。結合キーに基づいてテーブルのペアを分散する場合、リーダーノードは、結合列に含まれている値に従って行をスライスにコロケーションします。このようにして、共通の列から一致する値が物理的に一緒に保存されます。

 **ALL 分散** 

 テーブル全体のコピーがすべてのノードに分散されます。EVEN 分散または KEY 分散によってテーブルの一部の行のみが各ノードに配置されている場合、ALL 分散を行うと、テーブルが関与しているあらゆる結合ですべての行が確実にコロケーションされるようになります。

 ALL 分散では、クラスタ内のノードの数だけ必要なストレージが増えるため、データをロードまたは更新したり、複数のテーブルに挿入したりするのに時間がかかります。ALL 分散は、比較的移動の少ないテーブル、つまり、更新頻度が低く、更新範囲が広くないテーブルに適しています。クエリ中に小さなテーブルを再分散するコストは低いため、小さいディメンションテーブルを DISTSTYLE ALL として定義しても大きな利点はありません。

**注記**  
 列のディストリビューションスタイルを指定した後、Amazon Redshift はクラスターレベルでデータ配信を処理します。Amazon Redshift は、データベースオブジェクト内でのデータをパーティション化するという概念を必要とせず、サポートしていません。テーブルスペースを作成したり、テーブルのパーティション化方式を定義したりする必要はありません。

シナリオによっては、テーブルの作成後にそのテーブルの分散スタイルを変更することができます。詳細については、「[ALTER TABLE](r_ALTER_TABLE.md)」を参照してください。テーブルの作成後にテーブルの分散スタイルを変更できない場合は、テーブルを再作成して新しいテーブルにディープコピーを作成できます。詳細については、[ディープコピーを実行する](performing-a-deep-copy.md) を参照してください。

# 分散スタイルの表示
<a name="viewing-distribution-styles"></a>

テーブルの分散スタイルを表示するには、PG\$1CLASS\$1INFO ビューまたは SVV\$1TABLE\$1INFO ビューに対してクエリを実行します。

テーブルの現在の分散スタイルは、PG\$1CLASS\$1INFO の RELEFFECTIVEDISTSTYLE 列に示されます。テーブルが自動分散を使用する場合、RELEFFECTIVEDISTSTYLE は 10、11、または 12 です。これは、効率的な分散スタイルが AUTO (ALL)、AUTO (EVEN)、または AUTO (KEY) のどれであるかを示します。テーブルが自動分散を使用する場合、分散スタイルには当初 AUTO (ALL) が表示され、その後テーブルが大きくなると AUTO (EVEN) または AUTO (KEY) に変更される場合があります。

次の表は、RELEFFECTIVEDISTSTYLE 列に含まれる各値の分散スタイルを示しています。


| RELEFFECTIVEDISTSTYLE | 現在の分散スタイル | 
| --- | --- | 
| 0 | EVEN | 
| 1 | KEY | 
| 8 | ALL | 
| 10 | AUTO (ALL) | 
| 11 | AUTO (EVEN) | 
| 12 | AUTO (KEY) | 

テーブルの現在の分散スタイルは、SVV\$1TABLE\$1INFO の DISTSTYLE 列に示されます。テーブルが分散スタイルを使用する場合、DISTSTYLE は AUTO (ALL)、AUTO (EVEN)、または AUTO (KEY) になります。

次の例では、3 つの分散スタイルと自動分散を使用して 4 つのテーブルを作成した後で、分散スタイルを表示するために SVV\$1TABLE\$1INFO に対するクエリを実行します。

```
create table public.dist_key (col1 int)
diststyle key distkey (col1);

insert into public.dist_key values (1);

create table public.dist_even (col1 int)
diststyle even;

insert into public.dist_even values (1);

create table public.dist_all (col1 int)
diststyle all;

insert into public.dist_all values (1);

create table public.dist_auto (col1 int);

insert into public.dist_auto values (1);

select "schema", "table", diststyle from SVV_TABLE_INFO
where "table" like 'dist%';

        schema   |    table        | diststyle
     ------------+-----------------+------------
      public     | dist_key        | KEY(col1)
      public     | dist_even       | EVEN
      public     | dist_all        | ALL
      public     | dist_auto       | AUTO(ALL)
```

# クエリパターンの評価
<a name="t_evaluating_query_patterns"></a>

 分散スタイルの選択は、データベース設計の 1 つの側面にすぎません。分散スタイルをシステム全体のコンテキストの中で検討し、クラスターサイズ、圧縮エンコード方法、ソートキー、テーブル制約など、他の重要な要因と分散の間でバランスを取ることが必要です。

 できる限り実際のデータに近いデータを使用してシステムをテストします。

分散スタイルについて適切な選択を行うには、Amazon Redshift アプリケーションのクエリパターンを理解しておく必要があります。システム内で最もコストの大きいクエリを特定し、それらのクエリの要求に基づいてデータベースの初期設計を行います。クエリの総コストを決定する要因には、クエリの実行に要する時間、およびクエリによって使用されるコンピューティングリソースの量などがあります。クエリのコストを決定するその他の要因には、クエリの実行頻度、他のクエリやデータベースのオペレーションに及ぼす影響の度合いなどがあります。

 最もコストの大きいクエリによって使用されるテーブルを特定し、クエリランタイムにおけるそれらのテーブルの役割を評価します。テーブルの結合および集計方法を検討します。

 このセクションに示すガイドラインに従って、各テーブルの分散スタイルを選択します。それが完了したら、テーブルを作成し、実際のデータにできるだけ近いデータをテーブルにロードします。次に、使用する予定のクエリの種類についてテーブルのテストを行います。クエリの説明プランを評価して、調整の余地を特定できます。ロード時間、ストレージスペース、およびクエリランタイムを比較して、システムの全体的な要件のバランスを取ります。

# 分散スタイルの指定
<a name="t_designating_distribution_styles"></a>

 このセクションでは、分散スタイルの指定に関する検討事項と推奨事項にスタースキーマを例として使用しています。データベース設計は、スタースキーマに基づいている場合もあれば、スタースキーマの変形または完全に異なるスキーマに基づいている場合もあります。Amazon Redshift は、選択したスキーマデザインで効果的に機能するように設計されています。このセクションで示す原則は、どの設計スキーマにも適用できます。

1.  **すべてのテーブルのプライマリキーと外部キーを指定します。**

   プライマリキーおよび外部キーの制約は、Amazon Redshift によって強制されることはありませんが、クエリプランの生成時にクエリオプティマイザによって使用されます。プライマリキーと外部キーを設定する場合は、アプリケーションがキーの有効性を維持する必要があります。

1.  **ファクトテーブルとその最大のディメンションテーブルを共通の列に分散します。**

   テーブルのサイズだけでなく、最も一般的な結合に関与しているデータセットのサイズにも基づいて、最大のディメンションを選択します。WHERE 句を使用したテーブルのフィルタリングが一般的に行われている場合は、そのテーブルの行の一部しか結合に関与しません。このようなテーブルが再分散に及ぼす影響は、より多くのデータを提供するサイズの小さなテーブルよりも小さくなります。ディメンションテーブルのプライマリキーとそれに対応するファクトテーブルの外部キーをいずれも DISTKEY として指定します。複数のテーブルが同じディストリビューションキーを使用している場合、これらのテーブルはファクトテーブルともコロケーションされます。ファクトテーブルに指定できる分散キーは 1 つだけです。別のキーを使用して結合しているテーブルは、ファクトテーブルとコロケーションされません。

1.  **他のディメンションテーブルの分散キーを指定します。**

   他のテーブルとの結合に最も一般的に使用される方法に応じて、プライマリキーまたは外部キーを使用してテーブルを分散させます。

1.  **一部のディメンションテーブルで ALL 分散を使用するよう変更すべきかどうかを評価します。**

   ファクトテーブルやその他の重要な結合テーブルとディメンションテーブルをコロケーションできない場合は、テーブル全体を全ノードに分散させることによってパフォーマンスを大幅に向上させることができます。ALL 分散を使用すると、ストレージ領域要件の増大、ロード時間の長期化、メンテナンス操作の増加を招くため、ALL 分散を選択する前にすべての要因を比較検討しておく必要があります。次のセクションでは、EXPLAIN プランを評価することによって ALL 分散の適用候補を特定する方法について説明します。

1.  **残りのテーブルに AUTO 分散を使用します。**

   テーブルがほとんど非正規化され、結合に関与していない場合や、別のディストリビューションスタイルとして何を選択すべきかが明らかでない場合は、AUTO 分散を使用します。

Amazon Redshift が適切な分散スタイルを選択できるようにするには、分散スタイルを明示的に指定しないでください。

# クエリプランの評価
<a name="c_data_redistribution"></a>

クエリプランを使用すると、分散スタイル最適化の候補を特定できます。

初期設計の決定を行った後で、テーブルを作成し、テーブルにデータをロードして、テーブルをテストします。実際のデータにできるだけ近いテストデータセットを使用します。比較のベースラインとして使用するロード時間を測定します。

実行する予定のクエリのうち、典型的な高コストクエリ、つまり結合と集計を使用するクエリを評価します。さまざまな設計オプションの実行時間を比較します。実行時間を比較する際は、最初のランタイムにはコンパイル時間が含まれるため、最初の時間はカウントしないでください。

**DS\$1DIST\$1NONE**  
対応するスライスはコンピューティングノードにコロケーションされているため、再分散は必要となりません。通常は、DS\$1DIST\$1NONE ステップ (ファクトテーブルと単一のディメンションテーブル間の結合) が 1 つあるだけです。

**DS\$1DIST\$1ALL\$1NONE**  
内部結合テーブルで DISTSTYLE ALL が使用されているため、再分散は必要となりません。テーブル全体が各ノードに配置されます。

**DS\$1DIST\$1INNER**  
内部テーブルが再分散されます。

**DS\$1DIST\$1OUTER**  
外部テーブルが再分散されます。

**DS\$1BCAST\$1INNER**  
内部テーブル全体のコピーがすべてのコンピューティングノードにブロードキャストされます。

**DS\$1DIST\$1ALL\$1INNER**  
外部テーブルで DISTSTYLE ALL が使用されるため、内部テーブル全体が単一スライスに再分散されます。

**DS\$1DIST\$1BOTH**  
両方のテーブルが再分散されます。

**DS\$1DIST\$1ERR**  
テーブルにディストリビューションスタイルが選択されていない場合。

DS\$1DIST\$1NONE と DS\$1DIST\$1ALL\$1NONE が好適です。この 2 つは、すべての結合がコロケーションされているため、そのステップで分散が必要とならなかったことを示します。

DS\$1DIST\$1INNER は、内部テーブルがノードに再分散されているため、ステップのコストが比較的高くなる可能性があることを意味します。DS\$1DIST\$1INNER は、外部テーブルが結合キーを使用してすでに正しく分散されていることを示します。これを DS\$1DIST\$1NONE に変換するには、内部テーブルの分散キーを結合キーに設定します。場合によっては、外部テーブルが結合キーを使用して配信されていないため、結合キーを使用して内部テーブルを配信できないことがあります。この場合、内部テーブルに ALL ディストリビューションを使用するかどうかを評価します。テーブルの更新頻度が低いか、更新範囲が広くない場合で、高い再ディストリビューションコストに対応できるだけの十分なテーブルサイズの場合は、ディストリビューションスタイルを ALL に変更してから、再びテストします。ALL 分散はロード時間の長期化を招くため、再テストする場合は、評価要因にロード時間を含めてください。

DS\$1DIST\$1ALL\$1INNER は好適ではありません。これは、外部テーブルで DISTSTYLE ALL が使用されているため、外部テーブル全体のコピーが各ノードに配置されるよう、内部テーブル全体が単一スライスに再分散されることを意味します。その結果、全ノードを使用した並列ランタイムのメリットを生かせず、単一ノードで結合が直列ランタイムになるという非効率が生じます。DISTSTYLE ALL は、内部結合テーブルでのみ使用するよう設計されています。代わりに、外部テーブルの分散キーを指定するか、EVEN 分散を使用してください。

DS\$1BCAST\$1INNER と DS\$1DIST\$1BOTH は好適ではありません。通常、これらの再分散は、再分散キーを使用してテーブルが結合されないために行われます。ファクトテーブルにまだ分散キーが指定されていない場合は、両方のテーブルの分散キーとして結合列を指定します。ファクトテーブルの別の列にディストリビューションキーがすでに指定されている場合は、この結合をコロケーションするためにディストリビューションキーを変更することが全般的なパフォーマンスの向上につながるかどうかを評価します。外部テーブルのディストリビューションキーを変更することが最適な選択肢でない場合は、内部テーブルに DISTSTYLE ALL を指定することによってコロケーションを実現できます。

 次の例は、DS\$1BCAST\$1INNER ラベルと DS\$1DIST\$1NONE ラベルを持つクエリプランの一部を示しています。

```
->  XN Hash Join DS_BCAST_INNER  (cost=112.50..3272334142.59 rows=170771 width=84)
        Hash Cond: ("outer".venueid = "inner".venueid)
        ->  XN Hash Join DS_BCAST_INNER  (cost=109.98..3167290276.71 rows=172456 width=47)
              Hash Cond: ("outer".eventid = "inner".eventid)
              ->  XN Merge Join DS_DIST_NONE  (cost=0.00..6286.47 rows=172456 width=30)
                    Merge Cond: ("outer".listid = "inner".listid)
                    ->  XN Seq Scan on listing  (cost=0.00..1924.97 rows=192497 width=14)
                    ->  XN Seq Scan on sales  (cost=0.00..1724.56 rows=172456 width=24)
```

DISTSTYLE ALL を使用するようディメンションテーブルに変更を加えると、同じクエリのクエリプランに DS\$1BCAST\$1INNER ではなく DS\$1DIST\$1ALL\$1NONE が表示されるようになります。また、結合ステップの相対的なコストも大幅に変化します。合計コストは前のクエリの `3272334142.59` と比べて `14142.59` です。

```
->  XN Hash Join DS_DIST_ALL_NONE  (cost=112.50..14142.59 rows=170771 width=84)
        Hash Cond: ("outer".venueid = "inner".venueid)
        ->  XN Hash Join DS_DIST_ALL_NONE  (cost=109.98..10276.71 rows=172456 width=47)
              Hash Cond: ("outer".eventid = "inner".eventid)
              ->  XN Merge Join DS_DIST_NONE  (cost=0.00..6286.47 rows=172456 width=30)
                    Merge Cond: ("outer".listid = "inner".listid)
                    ->  XN Seq Scan on listing  (cost=0.00..1924.97 rows=192497 width=14)
                    ->  XN Seq Scan on sales  (cost=0.00..1724.56 rows=172456 width=24)
```

# クエリプランの例
<a name="t_explain_plan_example"></a>

この例では、クエリプランを評価して分散最適化の機会を特定する方法を示します。

EXPLAIN コマンドを使用して次のクエリを実行し、クエリプランを作成します。

```
explain
select lastname, catname, venuename, venuecity, venuestate, eventname, 
month, sum(pricepaid) as buyercost, max(totalprice) as maxtotalprice
from category join event on category.catid = event.catid
join venue on venue.venueid = event.venueid
join sales on sales.eventid = event.eventid
join listing on sales.listid = listing.listid
join date on sales.dateid = date.dateid
join users on users.userid = sales.buyerid
group by lastname, catname, venuename, venuecity, venuestate, eventname, month
having sum(pricepaid)>9999
order by catname, buyercost desc;
```

TICKIT データベースでは、SALES がファクトテーブルであり、LISTING がその最大のディメンションです。テーブルをコロケーションするために、SALES は LISTING の外部キーである LISTID を使用して分散され、LISTING はそのプライマリキーである LISTID を使用して分散されます。次の例は、SALES および LISTING の CREATE TABLE コマンドを示しています。

```
create table sales(
	salesid integer not null,
	listid integer not null distkey,
	sellerid integer not null,
	buyerid integer not null,
	eventid integer not null encode mostly16,
	dateid smallint not null,
	qtysold smallint not null encode mostly8,
	pricepaid decimal(8,2) encode delta32k,
	commission decimal(8,2) encode delta32k,
	saletime timestamp,
	primary key(salesid),
	foreign key(listid) references listing(listid),
	foreign key(sellerid) references users(userid),
	foreign key(buyerid) references users(userid),
	foreign key(dateid) references date(dateid))
        sortkey(listid,sellerid);

create table listing(
	listid integer not null distkey sortkey,
	sellerid integer not null,
	eventid integer not null encode mostly16,
	dateid smallint not null,
	numtickets smallint not null encode mostly8,
	priceperticket decimal(8,2) encode bytedict,
	totalprice decimal(8,2) encode mostly32,
	listtime timestamp,
	primary key(listid),
	foreign key(sellerid) references users(userid),
	foreign key(eventid) references event(eventid),
	foreign key(dateid) references date(dateid));
```

次のクエリプランでは、SALES および LISTING を使用した結合のマージ結合ステップに、そのステップで再分散が必要とならないことを意味する DS\$1DIST\$1NONE が示されています。ただし、クエリプランを上に移動するとわかるとおり、他の内部結合には、クエリ実行の一環として内部テーブルがブロードキャストされることを意味する DS\$1BCAST\$1INNER が示されています。キー分散を使用してコロケーションできるテーブルは 1 ペアのみであるため、5 つのテーブルを再ブロードキャストする必要があります。

```
QUERY PLAN
XN Merge  (cost=1015345167117.54..1015345167544.46 rows=1000 width=103)
  Merge Key: category.catname, sum(sales.pricepaid)
  ->  XN Network  (cost=1015345167117.54..1015345167544.46 rows=170771 width=103)
        Send to leader
        ->  XN Sort  (cost=1015345167117.54..1015345167544.46 rows=170771 width=103)
              Sort Key: category.catname, sum(sales.pricepaid)
              ->  XN HashAggregate  (cost=15345150568.37..15345152276.08 rows=170771 width=103)
                    Filter: (sum(pricepaid) > 9999.00)
	                    ->  XN Hash Join DS_BCAST_INNER  (cost=742.08..15345146299.10 rows=170771 width=103)
	                          Hash Cond: ("outer".catid = "inner".catid)
	                          ->  XN Hash Join DS_BCAST_INNER  (cost=741.94..15342942456.61 rows=170771 width=97)
	                                Hash Cond: ("outer".dateid = "inner".dateid)
	                                ->  XN Hash Join DS_BCAST_INNER  (cost=737.38..15269938609.81 rows=170766 width=90)
	                                      Hash Cond: ("outer".buyerid = "inner".userid)
	                                      ->  XN Hash Join DS_BCAST_INNER  (cost=112.50..3272334142.59 rows=170771 width=84)
	                                            Hash Cond: ("outer".venueid = "inner".venueid)
	                                            ->  XN Hash Join DS_BCAST_INNER  (cost=109.98..3167290276.71 rows=172456 width=47)
	                                                  Hash Cond: ("outer".eventid = "inner".eventid)
	                                                  ->  XN Merge Join DS_DIST_NONE  (cost=0.00..6286.47 rows=172456 width=30)
	                                                        Merge Cond: ("outer".listid = "inner".listid)
	                                                        ->  XN Seq Scan on listing  (cost=0.00..1924.97 rows=192497 width=14)
	                                                        ->  XN Seq Scan on sales  (cost=0.00..1724.56 rows=172456 width=24)
	                                                  ->  XN Hash  (cost=87.98..87.98 rows=8798 width=25)
	                                                        ->  XN Seq Scan on event  (cost=0.00..87.98 rows=8798 width=25)
	                                            ->  XN Hash  (cost=2.02..2.02 rows=202 width=41)
	                                                  ->  XN Seq Scan on venue  (cost=0.00..2.02 rows=202 width=41)
	                                      ->  XN Hash  (cost=499.90..499.90 rows=49990 width=14)
	                                            ->  XN Seq Scan on users  (cost=0.00..499.90 rows=49990 width=14)
	                                ->  XN Hash  (cost=3.65..3.65 rows=365 width=11)
	                                      ->  XN Seq Scan on date  (cost=0.00..3.65 rows=365 width=11)
	                          ->  XN Hash  (cost=0.11..0.11 rows=11 width=10)
	                                ->  XN Seq Scan on category  (cost=0.00..0.11 rows=11 width=10)
```

DISTSTYLE ALL を使用してテーブルを変更することは 1 つの解決策です。

```
ALTER TABLE users ALTER DISTSTYLE ALL;
ALTER TABLE venue ALTER DISTSTYLE ALL;
ALTER TABLE category ALTER DISTSTYLE ALL;
ALTER TABLE date ALTER DISTSTYLE ALL;
ALTER TABLE event ALTER DISTSTYLE ALL;
```

EXPLAIN を使用して同じクエリを再実行し、新しいクエリプランを検証します。DISTSTYLE ALL を使用して全ノードにデータが分散されたため再分散が必要とならないことを意味する DS\$1DIST\$1ALL\$1NONE が、結合に表示されるようになります。

```
QUERY PLAN
XN Merge  (cost=1000000047117.54..1000000047544.46 rows=1000 width=103)
  Merge Key: category.catname, sum(sales.pricepaid)
  ->  XN Network  (cost=1000000047117.54..1000000047544.46 rows=170771 width=103)
        Send to leader
        ->  XN Sort  (cost=1000000047117.54..1000000047544.46 rows=170771 width=103)
              Sort Key: category.catname, sum(sales.pricepaid)
              ->  XN HashAggregate  (cost=30568.37..32276.08 rows=170771 width=103)
                    Filter: (sum(pricepaid) > 9999.00)
                    ->  XN Hash Join DS_DIST_ALL_NONE  (cost=742.08..26299.10 rows=170771 width=103)
                          Hash Cond: ("outer".buyerid = "inner".userid)
                          ->  XN Hash Join DS_DIST_ALL_NONE  (cost=117.20..21831.99 rows=170766 width=97)
                                Hash Cond: ("outer".dateid = "inner".dateid)
                                ->  XN Hash Join DS_DIST_ALL_NONE  (cost=112.64..17985.08 rows=170771 width=90)
                                      Hash Cond: ("outer".catid = "inner".catid)
                                      ->  XN Hash Join DS_DIST_ALL_NONE  (cost=112.50..14142.59 rows=170771 width=84)
                                            Hash Cond: ("outer".venueid = "inner".venueid)
                                            ->  XN Hash Join DS_DIST_ALL_NONE  (cost=109.98..10276.71 rows=172456 width=47)
                                                  Hash Cond: ("outer".eventid = "inner".eventid)
                                                  ->  XN Merge Join DS_DIST_NONE  (cost=0.00..6286.47 rows=172456 width=30)
                                                        Merge Cond: ("outer".listid = "inner".listid)
                                                        ->  XN Seq Scan on listing  (cost=0.00..1924.97 rows=192497 width=14)
                                                        ->  XN Seq Scan on sales  (cost=0.00..1724.56 rows=172456 width=24)
                                                  ->  XN Hash  (cost=87.98..87.98 rows=8798 width=25)
                                                        ->  XN Seq Scan on event  (cost=0.00..87.98 rows=8798 width=25)
                                            ->  XN Hash  (cost=2.02..2.02 rows=202 width=41)
                                                  ->  XN Seq Scan on venue  (cost=0.00..2.02 rows=202 width=41)
                                      ->  XN Hash  (cost=0.11..0.11 rows=11 width=10)
                                            ->  XN Seq Scan on category  (cost=0.00..0.11 rows=11 width=10)
                                ->  XN Hash  (cost=3.65..3.65 rows=365 width=11)
                                      ->  XN Seq Scan on date  (cost=0.00..3.65 rows=365 width=11)
                          ->  XN Hash  (cost=499.90..499.90 rows=49990 width=14)
                                ->  XN Seq Scan on users  (cost=0.00..499.90 rows=49990 width=14)
```

# 分散の例
<a name="c_Distribution_examples"></a>

次の例は、CREATE TABLE ステートメントで定義したオプションに応じてデータがどのように分散されるかを示しています。

## DISTKEY の例
<a name="c_Distribution_examples-distkey-examples"></a>

TICKIT データベースの USERS テーブルのスキーマを確認します。USERID が SORTKEY 列および DISTKEY 列として定義されています。

```
select "column", type, encoding, distkey, sortkey 
from pg_table_def where tablename = 'users';
    
    column     |          type          | encoding | distkey | sortkey
---------------+------------------------+----------+---------+---------
 userid        | integer                | none     | t       |       1
 username      | character(8)           | none     | f       |       0
 firstname     | character varying(30)  | text32k  | f       |       0

...
```

このテーブルの分散列として USERID を選択するのは適切です。SVV\$1DISKUSAGE システムビューに対してクエリを実行すると、テーブルが非常に均等に分散されていることがわかります。列数はゼロベースであるため、USERID は列 0 です。

```
select slice, col, num_values as rows, minvalue, maxvalue
from svv_diskusage
where name='users' and col=0 and rows>0
order by slice, col;

slice| col | rows  | minvalue | maxvalue
-----+-----+-------+----------+----------
0    | 0   | 12496 | 4        | 49987
1    | 0   | 12498 | 1        | 49988
2    | 0   | 12497 | 2        | 49989
3    | 0   | 12499 | 3        | 49990
(4 rows)
```

テーブルには 49,990 行が含まれます。行 (num\$1values) 列は、各スライスにほぼ同じ数の行が含まれることを示します。minvalue 列と maxvalue 列は、各スライスの値の範囲を示します。各スライスには、値のほぼ全範囲が含まれるため、各スライスは、ユーザー ID の範囲をフィルターするクエリの実行に参加する可能性が高くなります。

この例は、小規模なテストシステムでの分散を示しています。通常、スライスの合計数はこれよりかなり多くなります。

STATE 列を使用してよく参加または結合する場合は、STATE 列で分散する選択を行うことができます。次の例では、USERS テーブルと同じデータを含む新しいテーブルを作成し、DISTKEY を STATE 列に設定した場合を示しています。この場合、ディストリビューションは均等ではありません。スライス 0 (13,587 行) には、スライス 3 (10,150 行) よりも約 30% 多く行が含まれます。これよりかなり大きなテーブルでは、この量の分散スキューがあるとクエリ処理に悪影響を及ぼす可能性があります。

```
create table userskey distkey(state) as select * from users;

select slice, col, num_values as rows, minvalue, maxvalue from svv_diskusage
where name = 'userskey' and col=0 and rows>0
order by slice, col;

slice | col | rows  | minvalue | maxvalue
------+-----+-------+----------+----------
    0 |   0 | 13587 |        5 |    49989
    1 |   0 | 11245 |        2 |    49990
    2 |   0 | 15008 |        1 |    49976
    3 |   0 | 10150 |        4 |    49986
(4 rows)
```

## DISTSTYLE EVEN の例
<a name="c_Distribution_examples-diststyle-even-example"></a>

USERS テーブルと同じデータを含む新しいテーブルを作成し、DISTSTYLE を EVEN に設定した場合、行はスライス間で常に均等に分散されます。

```
create table userseven diststyle even as 
select * from users;

select slice, col, num_values as rows, minvalue, maxvalue from svv_diskusage
where name = 'userseven' and col=0 and rows>0
order by slice, col;

slice | col | rows  | minvalue | maxvalue
------+-----+-------+----------+----------
    0 |   0 | 12497 |        4 |    49990
    1 |   0 | 12498 |        8 |    49984
    2 |   0 | 12498 |        2 |    49988
    3 |   0 | 12497 |        1 |    49989  
(4 rows)
```

ただし、分散が特定の列に基づいて行われないので、特にテーブルが他のテーブルに結合される場合に、クエリ処理の質が低下する可能性があります。結合列で分散が行われないと、多くの場合、効率的に実行できるタイプの結合操作に影響を及ぼします。結合、集計、およびグループ化操作は、両方のテーブルがそれぞれの結合列で分散およびソートされる場合に最適化されます。

## DISTSTYLE ALL の例
<a name="c_Distribution_examples-diststyle-all-example"></a>

USERS テーブルと同じデータを使用して新しいテーブルを作成して、DISTSTYLE を ALL に設定すると、すべての行が各ノードの最初のスライスに分散されます。

```
select slice, col, num_values as rows, minvalue, maxvalue from svv_diskusage
where name = 'usersall' and col=0 and rows > 0
order by slice, col;

slice | col | rows  | minvalue | maxvalue
------+-----+-------+----------+----------
    0 |   0 | 49990 |        4 |    49990
    2 |   0 | 49990 |        2 |    49990

(4 rows)
```

# ソートキー
<a name="t_Sorting_data"></a>

**注記**  
`SORTKEY AUTO` を使用してテーブルを作成することをお勧めします。その場合、Amazon Redshift は自動テーブル最適化を使用してソートキーを選択します。詳細については、「[自動テーブル最適化](t_Creating_tables.md)」を参照してください。このセクションの残りの部分では、ソート順について詳しく説明します。

テーブルの作成時に、代わりにその 1 つ以上の列を*ソートキー*として定義することもできます。データが空のテーブルに最初にロードされると、行がディスク上にソート順に格納されます。ソートキー列に関する情報がクエリプランナーに渡され、プランナはこの情報を使用して、データのソート方法を利用するプランを構築します。詳細については、「[CREATE TABLE](r_CREATE_TABLE_NEW.md)」を参照してください。ソートキーを作成する際のベストプラクティスについては、「[最良のソートキーの選択](c_best-practices-sort-key.md)」を参照してください。

ソートは、範囲が制限された述語を効率的に処理することができます。Amazon Redshift は、列データを 1 MB のディスクブロックに保存します。各ブロックの最小値と最大値がメタデータの一部として格納されます。範囲が制限された述語をクエリが使用する際には、クエリプロセッサはこの最小値と最大値を使用します。これにより、テーブルスキャン中に多数のブロックをすばやくスキップすることができます。例えば、日付でソートされた 5 年間のデータがテーブルに保存されており、クエリによって 1 か月間の日付範囲が指定されているとします。この場合、スキャンからディスクブロックの最大 98% を削除できます。データがソートされない場合は、より多くの (場合によっては、すべての) ディスクブロックをスキャンする必要があります。

複合キーまたはインターリーブソートキーを指定できます。複合ソートキーは、クエリ述語が、ソートキー列のサブセットの順序である*プレフィックス*を使用する場合に効果的です。インターリーブソートキーは、ソートキーの各列に同じ重み付けをするため、クエリ述語が任意の順序でソートキーを構成する列のサブセットを使用できます。

選択されたソートキーがクエリパフォーマンスに与える影響を把握するには、[EXPLAIN](r_EXPLAIN.md) コマンドを使用します。詳細については、「[クエリプランと実行ワークフロー](c-query-planning.md)」を参照してください。

ソートタイプを定義するには、CREATE TABLE または CREATE TABLE AS ステートメントで INTERLEAVED または COMPOUND キーワードを使用します。デフォルトは COMPOUND です。INSERT、UPDATE、または DELETE オペレーションを使用してテーブルを定期的に更新する場合は、COMPOUND を使用することをお勧めします。INTERLEAVED ソートキーは最大 8 列で使用できます。データとクラスターのサイズに応じて、VACUUM REINDEX は、インターリーブソートキーを分析する目的で追加パスを作成するため、VACUUM FULL よりも大幅に実行時間が長くなります。インターリーブテーブルでは、ソート操作およびマージ操作の時間が長くなる場合があります。これは、インターリーブソートでは、複合ソートよりも多くの行の再調整が必要になる可能性があるためです。

テーブルのソートキーを表示するには、[SVV\$1TABLE\$1INFO](r_SVV_TABLE_INFO.md) システムビューに対してクエリを実行します。

**Topics**
+ [多次元データレイアウトのソート](t_Sorting_mutidimensional-sort-key.md)
+ [複合ソートキー](t_Sorting_data-compound.md)
+ [インターリーブソートキー](t_Sorting_data-interleaved.md)

# 多次元データレイアウトのソート
<a name="t_Sorting_mutidimensional-sort-key"></a>

多次元データレイアウトソートキーは、ワークロード内の反復述語に基づく AUTO ソートキータイプの一つです。ワークロードに反復述語がある場合、Amazon Redshift は反復述語を満たすデータ行をコロケーションすることでテーブルスキャンのパフォーマンスを向上させることができます。多次元データレイアウトソートキーでは、テーブルのデータを厳密な列順序で保存する代わりに、ワークロードに現れる反復述語を分析してデータを格納します。1 つのワークロードに複数の反復述語が見られる場合があります。ワークロードによっては、このようなソートキーを使用すると多くの述語のパフォーマンスが向上します。Amazon Redshift は、このソートキーメソッドを `AUTO` ソートキーで定義されたテーブルに使用すべきかどうかを自動的に判断します。

例えば、データを列の順序でソートしたテーブルがあるとします。多くのデータブロックを調べて、それらがワークロードの述語を満たしているかどうかを判断する必要があるかもしれません。ただし、データが述語順にディスクに保存されている場合は、クエリを満たすためにスキャンする必要があるブロックの数が少なくなります。このような場合は、多次元データレイアウトソートキーを使用すると便利です。

クエリが多次元データレイアウトキーを使用しているかどうかを確認するには、[SYS\$1QUERY\$1DETAIL](SYS_QUERY_DETAIL.md) ビューの `step_attribute` 列を参照してください。値が `multi-dimensional` の場合、クエリには多次元データレイアウトが使用されています。

Amazon Redshift が多次元データレイアウトソートキーを使用しないようにするには、`SORTKEY AUTO` 以外の別のテーブルソートキーオプションを選択します。SORTKEY オプションの詳細については、「[CREATE TABLE](r_CREATE_TABLE_NEW.md)」を参照してください。

# 複合ソートキー
<a name="t_Sorting_data-compound"></a>

 複合キーは、ソートキー定義内にリストされているすべての列で構成されています。順序はリストされている順です。複合ソートキーは、クエリのフィルターがソートキーのプレフィックスを使用してフィルターや結合などの条件を適用する場合に便利です。複合ソートを実行する利点は、クエリがセカンダリソート列のみに依存しプライマリ列を参照しない場合には薄くなります。COMPOUND はデフォルトのソート形式です。

複合ソートキーで、結合、GROUP BY および ORDER BY 操作、PARTITION BY や ORDER BY を使用したウィンドウ関数の速度が上がる場合があります。例えば、データが結合列で分散および事前にソートされる場合は、ハッシュ結合よりも迅速なことの多いマージ結合が適しています。複合ソートキーは、圧縮の向上にも役立ちます。

すでにデータが含まれているソート済みテーブルに行を追加すると、未ソートのリージョンが増加し、パフォーマンスに大きな影響が生じます。影響は、テーブルがインターリーブソートを使用する場合、特にソート列が日付やタイムスタンプの列など一定間隔で増加するデータを含む場合、いっそう大きくなります。定期的に VACUUM 操作を実行してください。特に大量のデータをロードした後は、データを再ソートし再分析するために必要です。詳細については、「[未ソートリージョンのサイズを管理する](vacuum-managing-vacuum-times.md#r_vacuum_diskspacereqs)」を参照してください。バキューム処理を実行してデータを再ソートした後は、ANALYZE コマンドを実行してクエリプランナー用の統計メタデータを更新することをお勧めします。詳細については、「[テーブルを分析する](t_Analyzing_tables.md)」を参照してください。

# インターリーブソートキー
<a name="t_Sorting_data-interleaved"></a>

インターリーブソートキーは、ソートキー内の各列または列のサブセットに同じ重み付けをします。複数のクエリが 1 つのフィルターで異なる列を使用する場合、インターリーブソート形式を使用することで、多くの場合これらのクエリのパフォーマンスが向上します。クエリがセカンダリソート列で制限述語を使用する場合、インターリーブソートは複合ソートに比べて大幅にクエリのパフォーマンスが向上します。

**重要**  
ID 列、日付、タイムスタンプなど、一定間隔で増加する属性を持つ列で、インターリーブソートキーを使用しないでください。

インターリーブソートキーの実行によって得られるパフォーマンスの改善は、ロードの増分とバキューム処理の回数によって異なります。

インターリーブソートは、例えば `select c_name from customer where c_region = 'ASIA'` のように WHERE 句のソートキー列をフィルタリングする非常に選択的なクエリの場合に最も効果的です。インターリーブソートの効果は、制限されたソート済み列の数で向上します。

インターリーブソートは大きなテーブルに対してより効果的です。ソートは各スライスに適用されます。したがって、スライスごとに 1 MB のブロックを複数必要とする大きなテーブルの場合、インターリーブソートが最も効果的です。ここで、クエリプロセッサは、制限述語を使用してブロックのかなりの割合をスキップできます。テーブルが使用するブロック数を表示するには、[STV\$1BLOCKLIST](r_STV_BLOCKLIST.md) システムビューに対してクエリを実行します。

 単一の列を並べ替える場合、列の値に長い共通プレフィックスがある場合は、インターリーブソートの方が複合ソートよりもパフォーマンスがいい場合があります。例えば、URL は一般的に「http://www」で始まります。複合ソートキーはプレフィックスから使用する文字数に制限があるため、大量のキーの重複が発生します。インターリーブソートは、ゾーンのマッピング値に内部圧縮方式を使用するため、長い共通プレフィックスがある列の値をよりよく識別できます。

 小さな Amazon Redshift プロビジョニングクラスターを Amazon Redshift Serverless に移行すると、Redshift はインターリーブソートキーと DISTSTYLE KEY の両方を持つテーブルを複合ソートキーに変換します。ただし、インターリーブソートキーのみを持つテーブルは変更されません。分散スタイルの詳細については、「[データディストリビューションスタイルの操作](https://docs.aws.amazon.com//redshift/latest/dg/t_Distributing_data.html)」を参照してください。
<a name="t_Sorting_data-interleaved-reindex"></a>
**VACUUM REINDEX**  
すでにデータが含まれているソート済みテーブルに行を追加すると、パフォーマンスが時間とともに悪化することがあります。この悪化は複合ソートとインターリーブソートの両方で発生しますが、インターリーブテーブルでより影響が大きくなります。VACUUM はソート順序を復元しますが、インターリーブテーブルの場合は操作に時間がかかります。これは、新規のインターリーブデータのマージを行う際に各データブロックの変更が必要になる場合があるためです。

テーブルが最初にロードされると、Amazon Redshift がソートキー列の値の分散を分析し、その情報を基に適切なインターリービングをソートキー列に実行します。テーブルが大きくなるにつれて、ソートキー列の値の分散は、特に日付またはタイムスタンプ列で、変化したり不均等になったりします。不均等が大きくなりすぎると、パフォーマンスに影響を与えます。ソートキーを再分析してパフォーマンスを復元するには、REINDEX キーワードとともに VACUUM コマンドを実行します。インターリーブテーブルの場合、データに対して追加の分析パスを取る必要があるため、VACUUM REINDEX は標準の VACUUM よりも時間がかかります。キーの分散スキューおよび直近のインデックス再作成時間を表示するには、[SVV\$1INTERLEAVED\$1COLUMNS](r_SVV_INTERLEAVED_COLUMNS.md) システムビューにクエリを実行します。

VACUUM の実行頻度および VACUUM REINDEX の実行時期についての詳細は、「[インデックスを再生成するかどうかの決定](vacuum-managing-vacuum-times.md#r_vacuum-decide-whether-to-reindex)」を参照してください。

# テーブルの制約
<a name="t_Defining_constraints"></a>

一意性、プライマリキー、および外部キーの制約は情報提供のみを目的としており、テーブルに値を入れるときに *Amazon Redshift によって強要されるわけではありません*。例えば、依存関係のあるテーブルにデータを挿入する場合、制約に違反していても挿入は成功します。ただし、プライマリキーと外部キーはプランニング時のヒントとして使用されます。アプリケーションの ETL プロセスまたは他の何らかのプロセスによってこれらのキーの整合性が強要される場合は、これらのキーを宣言する必要があります。

例えば、クエリプランナーは、特定の統計計算でプライマリキーと外部キーを使用します。これは、サブクエリの非相関化手法に影響を与える一意性と参照関係を推測するために行われます。これにより、多数の結合を配列し、冗長な結合を排除できます。

プランナはこれらのキーの関係を活用しますが、Amazon Redshift テーブルのすべてのキーがロード時に有効であることが前提となります。アプリケーションが無効な外部キーまたはプライマリキーを許可する場合、いくつかのクエリが不正な結果を返す可能性があります。例えば、プライマリキーが一意でない場合、SELECT DISTINCT クエリが重複した行を返すことがあります。有効かどうかわからない場合は、テーブルに対してキーの制約を定義しないでください。ただし、有効だとわかっている場合は、プライマリキー、外部キー、および一意性の制約を必ず宣言してください。

Amazon Redshift は、NOT NULL 列の制約を適用*します*。

テーブルの制約の詳細については、「[CREATE TABLE](r_CREATE_TABLE_NEW.md)」を参照してください。依存関係のあるテーブルを削除する方法については、「[DROP TABLE](r_DROP_TABLE.md)」を参照してください。