kikeda1104's blog

備忘録・技術に関することを書いています。(webエンジニア)

RedShiftのエンコード

前回の記事では、テーブル定義まで進めて検証しましたが、今回はエンコードについて書いていきます。

前提

  • RedShift

エンコード

メリットは下記の通りです。

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

エンコードの定義方法は、カラムのデータ型、データ種類、データ数、連続性、データをみて選択可能な圧縮エンコードからテーブル定義(create table, alter table)と合わせて手動で定義するか、COPYコマンドを利用して自動圧縮エンコードを選択することができます。自動圧縮エンコードが推奨されていますが、サンプルデータがスライスで100000以上あることが条件になっていますので、それ以外については手動で選択することになります。(この条件値は変更可能ですが、100000が推奨値になっています)

エンコードの種類
  • デフォルト ソートキーとして定義されている、もしくは、BOOLEAN, REAL, DOUBLE PRECISION型の場合、デフォルトでROWエンコードになる。 他の型はデフォルトはLZOエンコードになる。

  • rawエンコード

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

ソートキー、BOOLEANでraw型がデフォルトになっています。

ただし、create tableで、エンコードを定義せずに実行すると、全てのカラムがrawエンコードが設定されています。

  • ランレングスエンコード

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

ステータスをStringで表記しているカラムがあるので、ランレングスエンコードを適用します。

  • text255 および text32k エンコード

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

繰り返し出てくる単語が多ければ利用する。

  • LZOエンコード

    LZO エンコードは、非常に高い圧縮率と良好なパフォーマンスを実現します。LZO エンコードは、非常に長い文字列を格納する CHAR および VARCHAR 列、特に製品説明、ユーザーコメント、JSON 文字列などの自由形式テキストに適しています。LZO は、ソートキー、および BOOLEAN、REAL、または DOUBLE PRECISION データ型として定義された列として指定された列以外のエンコードのデフォルトです。

データ型によってはCOPYコマンドを実行した際に、十分なサンプルデータがある場合にデフォルトでエンコードとして指定される。

  • Mostly エンコード

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

  • デルタエンコード

    デルタエンコードは、日時列にとって非常に有用です。 デルタエンコードは、列内の連続する値間の差を記録することにより、データを圧縮します。この差は、ディスク上の列値の各ブロックに対する個別のディクショナリに記録されます (Amazon Redshift ディスクブロックは 1 MB を占有します)。たとえば、連続する 10 個の整数 1~10 が列に含まれる場合、最初の整数は 4 バイト整数 (+ 1 バイトのフラグ) として格納され、次の 9 個の整数は、前の値よりも 1 大きいことを示す値 1 の単一バイトとしてそれぞれ格納されます。

  • Zstandard エンコード

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

手動定義

// テーブル定義
create table books
(
  id BIGINT NOT NULL PRIMARY KEY encode zstd,
  name VARCHAR(255)  encode zstd
);

テーブルを作成する際に定義する。(alter tableも可能)

推奨エンコード

既存テーブルに推奨されるエンコードを表示

// 十分なサンプルデータがあるケース
analyze compression table_name;

// 結果(サンプル)

    Table    |     Column      | Encoding | Est_reduction_pct
-------------+-----------------+----------+-------------------
 table_name | id              | zstd     | 7.75
 table_name | quantity | zstd     | 52.35


// idはBIGINTではあるけど、delta32k,MOSTLY32より推奨?されていることに疑問はある。

// 十分なサンプルデータがないケース
analyze compression table_name;

// 結果(サンプル)

 Table |       Column       | Encoding | Est_reduction_pct
-------+--------------------+----------+-------------------
 table_name | id                 | raw      | 0.00
 table_name | name               | raw      | 0.00

// サンプルデータ足りないためにrawエンコードを推奨に出している。

Est_reduction_pctは、zstdエンコードの圧縮可能率になります。

エンコードの自動定義

COPYコマンドがデフォルトでは、空のテーブルに対して実行する場合、、rawエンコードか指定なしの場合に自動圧縮します。また、テーブルのエンコード定義を無視して、自動圧縮を有効したい場合は、COMPUPDATEオプションをONにします。OFFで自動圧縮を無効にします。

すでにデータが入っているテーブルには、自動圧縮は適用されない。

課題

  • クエリの実行時間の計測 公式が掲載している内容に基づき計測をする。実行するクエリ、回線速度の変化があり、計測が難しいですが、この辺りの誤差は踏まえて計測値を信じて、ソートキー、エンコード、分散スタイルを選択する。

  • 圧縮エンコードの選択 rawエンコードを利用した方が、そのほかの圧縮エンコードを使うより最適な可能性もある。

参考

text255 および text32k エンコード - Amazon Redshift

ステップ 5: 圧縮エンコードを確認する - Amazon Redshift

例: CUSTOMER テーブルの圧縮エンコードの選択 - Amazon Redshift