Amazon Redshiftは、データウェアハウスとデータレイク全体でペタバイト(PB)のデータを高速でシンプルかつコスト効率よく分析することができるデータウェアハウスであり、ML(機械学習)、MPP(超並列処理)、SSD(ソリッドステートドライブ)ディスクの列指向ストレージを組み合わせることで、他のデータウェアハウスの10倍のパフォーマンスを実現することができます。

ただ、これだけのパワーがあっても、クエリのパフォーマンスにばらつきがあったり、ワークロードのスケーリングに課題があったりする可能性があります。なので Amazon Redshift のパフォーマンス最適化は、データ量、ユーザー、クラスタの増加に合わせて、前もって熟考した計画を立て、継続的にモニタリングすることが重要です。

速く、安く、簡単にスケールアップできるクラスターの運用

本記事では、Redshift のパフォーマンスの調整のためのベストプラクティスを15例ご紹介します。このプラクティスにより、市場のどの製品よりも安くて速くて、スケーリングしやすいクラスタが手に入るでしょう。

以下は、パフォーマンス調整のテクニック15選の概要です:

目次

Amazon Redshiftの使い方

Integrate.ioでは、主要なプラットフォームの一部として、Amazon Redshift が使われていますが、本記事では、3年以上にわたる複数の大規模な Redshift クラスターの運用で得られた見解をまとめました

Integrate.ioは、データエンジニアが極めて重要なデータの流れを見守るための単一のモニタリングダッシュボードを提供する分析プラットフォームです。

Integrate.io では、大量のデータのほぼリアルタイムでのバッチ処理のためにAmazon Redshift が使われており、データパイプラインは、1日あたり200億行以上を処理しています。データは、Amazon Redshift から DBLINK(データベースリンク)経由で RDS(リモートデスクトップサービス)と Amazon Elasticsearch Service に動かされることによって、アプリケーションに提供されています。

1.カスタムの WLM(ワークロードマネージャー)キューを作成する

Amazon Redshift の WLM(ワークロードマネージャ)は、クエリのパフォーマンスを管理するのに重要です。Amazon Redshift はキューイングモデルでクエリを実行しますが、デフォルトの WLM の構成では、5つのスロットを持つ単一のキューがあります。ただこのデフォルトの構成ではほぼ99%うまくいかないので、微調整が必要です。

ワークロードに合わせてWLMを構成することで、主に以下の2つのメリットが得られます:

  1. 同時実行やメモリなどの十分なリソースを与えることによってワークロードが拡張される
  2. バッチ処理などの予測可能なワークロードを、レポートツールのアドホッククエリなどの予測不可能なワークロードと分離して保護される

合計で最大50のスロットの最大8つのキューが可能であり、クエリは、デフォルトでは1つのスロットで実行されます。クエリは特定のルールを使ってキューにルーティングすることができ、WLMを正しい方法で設定することで、キューの待ち時間やディスクベースのクエリが解消されます。

ワークロードに合わせたWLMのセットアップには、以下の4ステップを踏むことをお勧めします:

  1. ユーザーを分ける
  2. ワークロードを確定する
  3. ユーザーをワークロードにグループ分けする
  4. キューごとのスロット数とメモリー比率を選ぶ

thumbnail image

パフォーマンス向上のための Redshift WLM の設定ガイドでは、キューの待ち時間をなくし、ディスクベースのクエリを減らすための4ステップのプロセスが説明されています。どちらもクラスタの速度を落とすので、この Redshift パフォーマンス調整のテクニックを詳しく見てみましょう。

キューのスロット数をピーク時の混雑度に合わせることで、キューの待ち時間を解消する

Redshift を一定期間使っていると、これまで2秒くらいで動いていたクエリが、かなり遅い速度で動き始めるという状況に出くわしたことがあるかもしれません。その原因として最も多いのはキューイングです。同時実行するクエリの数に対して、クラスタのスロット数が少なすぎるため、クエリがキューで待たされていたのです。

デフォルトの設定では、キュー1つでクエリ5つを同時に実行することができます。つまり、クエリが5つ実行されている場合、6つ目のクエリはスロットが空くまでキューに入ることになるということです。

目的は、クエリがキューで待たされることがないようにすることであり、それはキューのスロットカウントと、そのキューで実行されているクエリの実際の同時性を一致させることによって達成されます。

そして、キューの待ち時間は以下によって解消されます:

  1. キューのスロット数を増やす
  2. クエリを1日中均等に分散させることで、同時実行を減らす

この方法には、SQA(Amazon Redshift のショートクエリアクセラレーション )を正しい方法で使ってSQAのデメリットを回避することができるという、もう一つメリットがあります。SQAを有効にすると、クラスタ内でメモリを消費し、それによってディスクベースのクエリにたどり着けます。

キューに十分なメモリを割り当てることで、ディスクベースのクエリを減らす

キューイングの解消のためにスロット数を増やすと、ディスクベースのクエリという副作用が発生することがあります。「ディスクベース」とは、クエリがRAM(ランダムアクセスメモリ)を使い果たし、ハードディスクを使うようになるということです。クエリのメモリがそのキューの「1スロットあたりのメモリ」を超えるので、クエリがディスクベースになるのです。

スロットあたりのメモリは、次のように計算されます:

キューに割り当てられたメモリ ÷ スロットの数

各キューには、WLMキューを構成する際に設定する値になるクラスタのメモリの一定割合が割り当てられるため、スロットを増やすとスロットあたりのメモリは減少します。

ディスクベースのクエリでは、以下の大きな問題が発生します:

  1. クエリはより多くのI/Oを必要とするため速度が落ちる
  2. 同時並行性が高くなり、より多くの待ち行列が発生する。

ディスクベースのクエリの頻度が上がると、連鎖反応が起こる可能性があります。I/Oが増えればCPUも増え、クエリの実行速度は落ち、それによって全体の同時実行率が上がります。

目安として、クエリの10%未満がディスクベースになるようなキューを維持しましょう。

Integrate.io のスループットおよびメモリ分析ダッシュボードだと、適切なスロット数とメモリ割合を見つけやすくなります。関連するメトリクスを直感的な時系列ダッシュボードで確認できれば、各キューに適切なスロット数とメモリの割合を割り当てやすくなります。

クラスタに適したスロット数とメモリの割合を見つけましょう

2.CDC(変更データキャプチャ)を使う

Amazon Redshift のCOPY コマンドは、並列アーキテクチャを活用し、Redshift にデータを移動するための推奨方法です。COPYコマンドは最適化されていますが、COPY の操作はまだコストがかかるので、ベストプラクティスは、「必要な行だけのコピー」です。

取り込まれる行数を最小限にすることが目標であり、それには、ETLツールが確実に前回から変更されたデータのみをコピーするようにするのが一番です。そうでないと、以下の問題が発生します:

  1. ディスクの使用率の頻繁な急上昇で、より多くの空き容量が必要になる。
  2. I/Oを使用し、VACUUM の操作の必要性を高める冗長データが削除される(重複排除)。

thumbnail image

ディスクの使用率の急上昇

ここでは、CDCの操作例をご紹介します:

thumbnail image

3.カラムのエンコード(符号化)を使う

圧縮されていない大きなカラムに圧縮を加えると、クラスタのパフォーマンスに大きな影響を与えます。

圧縮では以下が実現します:

  1. ストレージ使用量の削減。ファイル圧縮は、データのサイズフットプリントを減らすので、クラスタノードのディスクの使用量を減らすことができます。
  2. クエリパフォーマンスの向上。スキャンやジョインするデータが少なく、I/Oの使用量が制限されるため、クエリの速度が上がります。

また、ZSTD(Zstandard)の符号化アルゴリズムの使用をお勧めします。この比較的新しいアルゴリズムは、高い圧縮率を提供し、Amazon Redshift の全データ型において機能します。ZSTDは、長い文字列と短い文字列が混在するVARCHARとCHARフィールドで特に優れており、他にもあるアルゴリズムとは違って、ストレージ使用率を上げる可能性は低いです。

ここでは、Amazon Redshift のロギングテーブル3つに ZSTD を適用した実例をご紹介します。平均50%以上のストレージ削減を実現しています!

thumbnail image

thumbnail image

thumbnail image

4.COPY ごとに ANALYZE しない

Amazon Redshift のCOPYコマンドは、データをテーブルに格納します。

以下の2つのコマンドの実行が、Redshift COPY コマンドのデフォルトの動作になります:

  1. “COPY ANALYZE PHASE 1|2”  
  2. “COPY ANALYZE $temp_table_name”

Amazon Redshift はこのコマンドを実行し、コピーされるデータの正しいエンコードを決定します。これは、テーブルが空である場合に便利かもしれませんが、以下のようなケースでは、余分なクエリは無駄なので排除されるべきです:

  1. UPSERTの一部など、一時的なテーブルにCOPYする場合
  2. テーブルにすでにデータが入っている場合:既存のテーブルの場合、エンコードの変更はできないので、COPYコマンドでより良いエンコードスタイルが存在すると判断されたとしても、深いコピー操作を行わなければ、テーブルのエンコードの変更はできません。

以下の例では、COPYコマンド1つで「analyze compression」のコマンド18個と「copy analyze」のコマンド1つが生成されます。

thumbnail image

thumbnail image

thumbnail image

余分なクエリは、Amazon Redshift 上で実行されている他のクエリにパフォーマンスの問題を引き起こす可能性があります。同時実行が増え、WLMキューのスロット数が飽和状態になる可能性があり、それによって他のクエリに待ち行列が発生してしまうのです。


それには、COPYコマンドのパラメータを調整して「COMPUPDATE OFF」と「STATUPDATE OFF」を追加するという解決策があります。このようなパラメータが、「UPSERT」中にこれらの機能を無効にしてくれるのです。

この設定で COPY コマンドを実行した場合の例を以下に出してみましょう:

thumbnail image

5.Redshift を OLTP データベースとして使わない

Django のようなアプリケーションフレームワークを Amazon Redshift に接続することはよくあることです。これは、アプリケーションで Redshift のデータを使用する場合、つまりOLTP(オンライントランザクション処理)シナリオで便利ですが、Amazon Redshift はOLAPデータベースであるため、このようなクエリをうまく処理できない可能性があります。

Redshift をOLTPデータベースとして使う場合、従来の RDBMS (リレーショナルデータベース管理システム)に存在するローレイテンシーがクエリには欠けている場合があるという問題があります。OLTP データベースとは違い、OLAPデータベースはインデックスを使いません。これは、Amazon Redshift の列指向のデータストレージ設計の結果であり、ビッグデータの分析ワークロードでより良いパフォーマンスを発揮するためのトレードオフとなっています。

生のプロダクションクラスタからこの例を考えてみましょう。ユーザー 'django_redshift' はテーブル 'search_word_level_course_vector' をクエリしていおり、 443,744 行のテーブルです。クエリは 374,372 回実行され、各クエリは1行返しました。

thumbnail image

各クエリは 443,744 行すべてをスキャンし、実行に約0.02秒かかり、1行を返します。

thumbnail image

クラスターに与える影響は、以下のように非常に劇的なものです:

  • 毎クエリ0.02秒でクエリ374,371個を処理すると、 7,487 秒(約125分)かかります。コミットキューはこのようなリクエストでバックアップされ、クラスタで実行されている他のクエリすべての実行時間に影響を与えます。

  • クエリのボリュームは同時実行性を高め、利用可能な WLM スロットの数#を超える可能性があり、その結果、そのキューで実行中の他のクエリのキュー待ち時間が発生してしまいます。

その問題解決には、以下のアプローチがあります:

  1. テーブルの443,744行を全選択するようにクエリを書き直し、アプリケーションメモリで各行を解析する。そうすることで、Redshift データベースから374,371のクエリが削除されます。このようなクエリ1つだと、125分ではなく、わずか数秒くらいしかかからないでしょう。
  2. Amazon RDS と DBLINK を使って、Redshif を OLTP として利用する。この方法については「Have your Postgres Cake and Eat it Too」の記事で詳しく説明しています。

6.テーブル結合に必要な場合のみ DISTKEY を使う

分散スタイルは、Amazon Redshift クラスターのノード間で、与えられたテーブルの行をどのように分散するかを決定するテーブルプロパティです。正しい分散スタイルの選択は、クエリのパフォーマンスにとって重要です。

thumbnail image

分散スタイルの選択の際に注意すべき点は、大きく分けて2つあります:

  1. ネットワークI/OやディスクI/Oのためにコストがかかるノード間のデータ移動を最小限に抑える。
  2. クエリのパフォーマンスを最大化し、行スキューを最小化するために、データをクラスタに均等に分散させる。(「行スキュー」については後述します。)

EVENベースの分散

デフォルトの分散スタイルは「EVEN」であり、ノードはすべて、与えられたテーブルに対して同じ数の行を含んでいます。

「EVEN」分散スタイルの利点は以下の通りです:

  • ノード全てに同じワークロードがあるため、テーブルスキャンが速い
  • 行スキューがないため、ノードのディスク使用率が同じ。(後ほど「行スキュー」とは何かをご説明します。)

ただし、2つのテーブルを JOIN(結合)する場合、「EVEN」分散は最適とは言えません。2つのテーブルを JOIN したときのことを考えてみましょう:

  1. テーブル1のデータを選択する
  2. テーブル2のデータを選択する
  3. データを単独のノードに移動する(コロケーション)
  4. そのノードのデータを結合し、結果を保存する

で、ここからクエリの実行が続きます。

EVEN分散では、ステップ3でノード間のデータ移動が必要であることはすぐわかります。これはネットワーク(ブロードキャスト)トラフィックを必要とし、クラスタ全体の I/O 使用率が増加するため、理想的ではありません。どちらの要因もクエリのレイテンシを増加させてしまいます。

JOINをもっと速くするためのKEYベースの分散

この問題を解決し、JOIN をもっと速くするために、Amazon Redshift にはKEYベースの分散スタイルがあります。KEYベースの分散では、Amazon Redshift によって、2つのテーブルにまたがる所定のカラムについて、ステップ3(単一ノードへのデータ移動)が必要なくなります。これは、データをノードに書き込む際に、あるアルゴリズムを適用することで実現され、このアルゴリズムによて、'DISTKEY'カラムに同じ値を持つ行は、確実に同じノード上に存在できるようにようになります。

では、JOINカラムの名前が「customer_id」である例を考えてみましょう。

  1. テーブル1のDISTKEYは "customer_id "であることが必要。
  2. テーブル2のDISTKEYは "customer_id "であることが必要。
  3. クエリ 1 は、「customer_id」でテーブル 1 とテーブル 2 を結合する。

この場合、テーブル1またはテーブル2が EVENベースの分散を使う場合よりも、クエリ1の実行速度が速くなります。

KEYベース分散のデメリット

でも、テーブル1に対して別のタイプのクエリを実行するとどうなるでしょうか?例えば、"customer_id "ではなく、別のカラムで JOIN するようなクエリでしょうか?あるいは、JOIN をまったく行わないとか?このようなカラムに JOIN しないクエリだと、実行速度が大幅に下がるかもしれません。

KEYベースの分散を使うことのデメリットは、主に2つあります。

  1. ノードのディスク使用率が均一でない: テーブルでKEYベースの分散を使い、DISTKEYカラムの値が均等に分散されていない場合に、行の傾きが発生し、その結果、あるノードではそのテーブルの行数が多くなってしまいます。
  2. クエリが遅くなる: 行数が異なると、そのテーブルに直接触れる SELECT のような他のクエリは、すべて少し遅くなります。例えばあるノードに次のノードよりも多くのデータがあると、クエリの実行は「最も多くの行がある」「最も遅い」ノードがリーダーノードにデータを送信するのを待たないといけなくなります。

KEYベースの分散を行う場合

KEYベースの配布がいいのは、最適化したい主要なクエリがある場合のみで、それ以外の場合は、EVENベースの分散を使いましょう。

EVEN 分散を使うと、以下のことが起こります:

  • 行スキューの解消
  • そのテーブルのSELECTの確実な最適化。

Integrate.ioでは、スキューのあるテーブルはとても見つけやすいです。『ストレージ分析(Storage Analysis)』のダッシュボードに入ったら、まず Node 0の使用率が常に100%に近いことに気づくでしょう。

これはおそらく、分散キーに問題があるということであり、そこから『テーブル分析(Table Analysis)』のダッシュボードに入ると、各テーブルの行スキューが表示されます。

thumbnail image

Amazon Redshift の 行スキューを簡単に発見・修正しましょう

7.正確なテーブル統計を維持する

Amazon Redshift は、全クエリに対してカスタムクエリの実行計画を構築します。与えられたクエリプランに対して、メモリの量が割り当てられ、メモリの割り当ては、JOIN やアグリゲーションのように、中間クエリ結果の保存に必要なメモリ量を推定することで決まります。

クエリプランは、JOINやアグリゲーションなどの中間結果の保存に必要なメモリ量を見積もることで、各クエリに一定量のメモリを割り当てます。

クエリでは、ディスクに流出しない(「ディスクベース」になる)ために十分なメモリを確保することが重要です。多すぎるメモリの割り当ても好ましくありません。クエリはメモリを共有しませんからね。必要以上にメモリを割り当てると、他のクエリが利用できなくなるため、メモリが無駄になるのです。

ここで重要なのは、このシステムは適応型ではないということです。もし計画が間違っていて、クエリが割り当てられたよりも多くの(または少ない)メモリを必要とする場合、実行エンジンはクエリがすでに実行を開始した後に戻ってメモリ割り当てを調整することはありません。

プランがおかしくなる原因は何でしょうか?よくあるのは、テーブルの行数です。

ANALYZE コマンドで、プランナーはテーブルの行数を正確かつ最新に把握できるようになります。統計が誤っている場合の例を見てみましょう。

例1:プランナーが思っているよりもテーブルの行数が多い

例えば、プランナーがクエリに割り当てるメモリが少なすぎるとしましょう。クエリの実行が始まると、割り当てられた以上のメモリが必要であることがわかり、それでクエリはディスクベースで実行されることになって、実行速度が遅くなります。

これは、十分なメモリを搭載したスロットでクエリを実行することで回避できたかもしれません。

例2:プランナーが思っているよりテーブルの行数が少ない。

ここで、プランナーがクエリに過剰なメモリを割り当てたと仮定してみましょう。クエリの実行が始まると、中間結果を格納するのに必要なメモリが、割り当てられた量より少ないことに気づきます。この場合、結果は以下の2つのどちらかになります:

  1. クエリがディスクベースになることはない。ただ、メモリを使いすぎたため、他のクエリがディスクベースになる可能性があります。
  2. クエリが実行されたスロットで使える以上のメモリが割り当てられ、クエリがディスクベースになってしまった。これは、最新の統計情報があれば回避できたはずです。

ANALYZE の実行

Amazon Redshift では、テーブルに対して ANALYZE コマンドを実行するタイミングを判断するのに「stats off」という統計情報を提供しています。「stats off」のメトリクスは、「実際の行数」と「プランナーによって見られる行数」との間の正のパーセンテージの差です。

thumbnail image

ベストプラクティスとして、「stats off」の割合が10%を超えるテーブルに対して ANALYZE の実行をお勧めします。

8.よりスマートなクエリを書く

Amazon Redshiftは、複数のノードで水平にスケールする「分散型のシェアードナッシングデータベース」であり、クエリの実行時間は以下と非常に密接な相関があります:

  • クエリが処理する行数およびデータの数
  • ノード間を移動するデータ量

以下は、お粗末に書かれたクエリの例と、それをより速く実行するための2つの最適化です。

thumbnail image

最適化その1:WHERE 句を使って処理する行を制限する。

クエリは、ノード間を移動するデータ量を最小限に抑えることで、より速く実行することができます。実際には、ステージ1つの結果が次のステージに反映されるようなマルチステージのクエリを書くときに注意が必要です。


この例のクエリの場合、WHERE 句を修正して必要な行だけを選ぶようにすれば、移動が必要なデータの量が最小限に抑えられ、クエリのスピードが上がります。

thumbnail image

最適化その2:スキャンするカラムを制限する

Amazon Redshift は列指向のデータベースです。その結果、テーブルをスキャンしても、各行全体を読むことはありません。代わりに、個々の列は、他の列を読む必要なくスキャンすることができます。

クエリに使うカラムのみを選ぶように注意が必要です。どんな場合でも以下を使うのはなるべく避けましょう。

‘SELECT *’

thumbnail image

この2つの最適化により、クエリの速度は劇的に上がります。

クエリの書き直しは、「言うは易く行うは難し」なんですけどね。なので、クエリの書き直しを推奨するダッシュボードである「クエリインサイト」が製品に組み込まれ、大幅な高速化が実現しました(30分かかっていた実行時間が30秒になった顧客もいます)。

また、Integrate.io のダッシュボードから直接ユーザーにメールを送り、あるクエリについて何が変更可能かを知らせることができます。

遅いクエリを瞬時に発見・修正しましょう

9.行スキュー(傾き)を避ける

行スキューは、テーブルでKEYベースの分散が使われており、DISTKEY 列の値が均等に分布していない場合に発生します。行スキューのメトリクスは、1からテーブルの行数までの正の整数であり、行スキューは、以下の比率になります:

  • テーブルの最多行数を含むノードの行数
  • テーブルの最小行数を含むノードの行数

thumbnail image


行スキューが大きいと、ノードのディスク使用量(コスト)が不均一になり、クエリ(パフォーマンス)が遅くなってしまいます。

下のチャートは実際の例を示しています。ディスクの使用率が偏っていると、単独つのノード(複数可)がそのテーブルに対してより多くの行を持つことになります。これは、ただ単独のノードが偏っているからという理由でクラスタのノードの追加が必要だとしたら、大きな(コストの)問題になり得ます。

thumbnail image

行スキューが高い場合、そのテーブルでストレートに SELECT を実行すると、他の場合よりも遅くなります。これは、あるノードに次のノードよりも多くのデータがあるためで、クエリーの実行は「最も遅い」ノードがリーダーにデータを送信するのを待たないといけないからです。

行スキューの解消には、選択肢が2つあります:

  1. ランダムな DISTKEY を選択する
  2. 分散スタイルを EVEN または ALL に変更する

行スキューを許容する例外は、単独のクエリを最適化することを意識的に決定した場合(のみ)です。詳しくは、本記事の「必要な場合のみDISTKEYを使う」のセクションを参照してください。

10.SQA を使う

SQA(ショートクエリーアクセラレーション)は、実行時間の短いクエリの実行のスピードを上げるものであり、特定のクエリを選択してキューをジャンプさせることで実行されます。クラスタが大きなクエリと小さなクエリを混在させて実行している場合に便利であり、その場合は、長いクエリの後ろに並ばないといけない小さなクエリが最初に実行されることになります。

Amazon Redshift のクラスタでは SQA がデフォルトで有効になっていますが、クラスタに他の調整を加えずにSQAを使うのが成功の秘訣ではありません。最初に引くべき他のレバーがあるんです。より速いクエリのために Amazon Redshift のSQA と WLM を使うためのクイックガイドをぜひご参照ください

11.S3でデータを圧縮する

Amazon Redshift の COPY コマンドは、Amazon Redshift にデータを移動するための推奨方法であり、Amazon Redshift の並列アーキテクチャを使ってデータを移動させたり、EMR、DynamoDB、SSH経由のリモートホストなどのさまざまなソースからファイルを読み込んだりできます。

大量のデータを読み込む際に S3 でファイルを圧縮することで、3つの目的が達成されます:

  1. S3へのより速いファイルアップロード
  2. S3ストレージの利用(コスト)低下
  3. ファイルの読み込みと同時に圧縮解除ができることによる、より速い読み込み処理

長時間の COPY コマンドは、Redshift のこのパフォーマンス調整テクニックで最も改善されます。

12.非常に長いテーブルを管理する

Amazon Redshift は、例えば50億行を超えるテーブルなどの非常に長いテーブルの集計に非常に適しています。ユースケースによっては、生データを Amazon Redshift に保存し、テーブルを縮小してその結果をデータパイプラインの後半で後続の小さなテーブルに保存することを求めるものもあります。

これは素晴らしいユースケースだと考えられますが、非常に大きなテーブルを管理するには、課題が2つあります:

  1. プルーニング(過去のデータを削除すること)が非常に高くつく可能性がある
  2. 長いテーブルの仕分けが非常に高くつく(あるいはできない)可能性がある

このセクションでは、このような長いテーブルの問題をより効率的に管理するためのアプローチについていくつか見ていきましょう。

非常に長いテーブルを PRUNE しやすくすべく UNION を使う

長いテーブルを整理するには、DELETE 操作の実行が必要であり、テーブルがディスクでいっぱいになるのを避けるために、かなり頻繁に実行する必要があります。

DELETE 操作のたびに、以下の3つのメンテナンスステップをテーブル上で実行する必要があります:

  1. 仕分け
  2. テーブルの上のスペース確保
  3. テーブルの統計情報の更新

非常に長いテーブルだと、このような操作は非常にコストがかかる可能性があります。

3つのステップを回避するには、その非常に長いテーブルを小さなテーブルに分割するといいでしょう。同じスキーマで、別々のテーブル名を持つテーブルを複数作成します。そのテーブルの行は、選択された 分割キー に基づいて分けられ、そのテーブルに INSERT するジョブは、パーティションスキームを認識していないといけません。

このテーブルから選択するには、元のテーブル名でビューを作成し、アプリケーションに一貫したビューを提供するのにUNION 指令を使います。

これには次のような利点があります:

  • VIEW は同じテーブル名を表示するので、アプリケーションは分割を気にする必要がない
  • プルーニング(枝刈り)は、単に「一番古い」テーブルを削除するだけであり、VACUUM の実行は不要。ドロップ操作は非常に安価で、すぐにスペースを取り戻すことができる。

ただ、この方法には欠点があります。UNION 操作は単一のテーブルをスキャンするほど速くはならないので、テーブルに対するS ELECT は少し遅くなります。でも環境によっては、非常に長いテーブルを維持する苦痛を避けるための小さなトレードオフになり得ます。

仕分け順でCOPY

仕分けはコストのかかる操作であることがわかりましたが、UPSERT メソッドを使って新しいデータをテーブルに COPY する場合、そのテーブルは仕分けが必要です。

UPSERT は、Amazon Redshift にコピーする際に、データの重複を解消する方法です。UPSERT 操作は、主キーを使って新しいレコードを既存のレコードとまとめます。一部の RDBMS は単一の「UPSERT」ステートメントに対応していますが、Amazon Redshift はそれに対応しておらず、代わりに、レコードをまとめるためのステージングテーブルを使う必要があります。

UPSERT は DELETE を実行するため、テーブルが未ソート状態になる可能性があります。

テーブルの仕分けを不要にする方法として、仕分け順で COPY する方法があります。

この方法の使用を検討する場合、以下のような注意点があります:

  • COPY にのみ有効である(通常の挿入ではない)
  • マニフェストの使用は、ファイルの順序が保証されていないので問題がある
  • テーブルの仕分けキーは1つしかない(インターリーブスタイルは非対応)
  • 仕分けのカラムは NOT NULL で、テーブルは100%仕分けされている(または空である)必要がある。
  • 新しい行は、削除のためにマークされた行などの既存の行よりも仕分け順が高くなる。

13.RA3ノードを使って、独立したコンピュートとストレージのスケーリング(拡張化)を実現する

2019年、Amazon は Redshift 用の RA3 ノードを発表しました。これは、自動データ消去、データプリフェッチやその他データ管理技術を駆使したものと組み合わせたローカル キャッシングに、大容量の SSD を使っています。RA3ノードがあれば、コンピュートとストレージを分離でき、コンピュートニーズに応じてクラスターを拡張できるので、分析の総コストが削減されます。

RA3ノードの基本的な考え方は、永続的なデータの保存にすべて S3 を使い、キャッシュにローカルディスクを使うことであり、データは S3からオンデマンドで取得できます。さらに、Redshift はホットデータ(使用頻度の高いデータ)を特定し、ローカルに置いておくことで高速な計算時間を実現し、RA3ノードクラスタは、AWSマネジメントコンソールから作成することができます。

14.使用頻度の低いデータには Amazon Redshift Spectrum を使う

Amazon Redshift は、破格設定で発売されました。コストを比較するために、1TBのデータを1年間保存する場合の価格($ / TB / 年)を見てみましょう。ds2.8xlargeノードの3年プランでは、価格は$ 934 / TB / 年に下がります。この価格帯は、データウェアハウスの世界では前代未聞のものです。

Amazon Redshift の顧客は、平均して毎年データが倍増しており、実際、それがパフォーマンス改善に注力することが重要である理由の1つです。データ量が増えるにつれて、パフォーマンスの管理はより大きな課題になりますからね。

ただ、ある時点で、このデータをすべて Amazon Redshift に保存するコストが高くつくようになります。数年分のデータの履歴を「永久に」維持するのは、高くつくかもしれません。また、規制上の理由から、データの削除ができない場合があります。

Amazon Redshift の価格は、クラスタのサイズに基づきます。つまり、コンピュートとストレージは連動しています。vCPUによる追加の計算能力は必要ないかもしれませんが、ストレージのためにノードを追加し続ける必要があります。


ただ、Amazon Redshift ではデータの保存が安価なため、過去の生データをすべて Redshift に保存することが初期動作としてよくありますが、データ量は増えていきます。また、速いけど高価な高密度なコンピュートノードを使いたいと思うかもしれませんが、多くの企業は、1年以上の資本コミットメントをしたくないと考えています。

そこで Amazon Redshift Spectrum の登場です。Redshift Spectrumを使えば、S3 データレイクにデータをそのまま残しておいて、Amazon Redshift 経由でクエリすることができます。つまり、コンピュートとストレージを切り離すことができるのです。このアプローチは、頻繁にアクセスしなくていいデータがある場合は便利です。「ホット」なデータは Amazon Redshift に、「コールド」なデータは S3 に置いときましょう。

thumbnail image

コストへの影響は相当なものになります。S3 の Standard Storage の価格は、281ドル/TB/年です。このように、Redshift Spectrum を使えば、両方の世界のベストを手に入れることができます。これは「データ・ティアリング」といいます。Amazon Redshift のパフォーマンスとともに、履歴データをすべて維持することができるのです。Redshift Spectrumでは、S3を使うとによるコスト削減の恩恵を受けられますね。

Amazon Redshift Spectrum: How Does It Enable a Data Lake?" の記事では、Amazon Athena や AWS Glue の利用も含め、データレイクアーキテクチャの一部として Redshift を使うことについて、さらに詳しく見ています。Redshift Spectrum といえば、Redshift クラスタのパフォーマンスを細かく調整するためのボーナスTipsをご紹介します。

15.S3データには列指向のフォーマットを使う

S3のデータは、Apache Parquet のような列指向のフォーマットで保存するのが効率的です。列指向のフォーマットは、行ベースのフォーマットと比べて、より良いパフォーマンスを発揮します。また、費用対効果の要素もあります。列指向のフォーマットでは、Redshift Spectrum は必要なデータレコードを持つカラムのみをスキャンし、すべてのカラムを読み込むわけではなく、スキャンしたデータ量に対して料金を支払うので、Apache Parquet はデータ分析コストの削減に繋がるのです。

さらに、頻繁にフィルタリングされるカラムを使ってデータを仕分けすることでParquet がさらに最適化され、Redshift および Redshift Spectrum の費用対効果が上がります。

Redshiftを最大限に活用しよう

Amazon Redshift は、低コストで高いパフォーマンスを提供するクラウドベースのデータウェアハウスですが、クエリパフォーマンスにムラがあったり、ワークロードのスケーリングに課題があったりするのは、Amazon Redshift に共通する問題です。なので、ここでご紹介した Redshift のパフォーマンス調整のテクニックを使って、クラスタのコストを下げてクエリパフォーマンスを上げ、データチームの生産性を上げましょう。

データエンジニアがスキルアップを目指すなら、週刊Webマガジンをぜひご購読ください。データエンジニアリングの最新動向を、メールでお届けします。