Amazon Redshift でディスク使用率が高くなる、またはいっぱいになる問題をトラブルシューティングする方法を教えてください。

最終更新日: 2020 年 10 月 15 日

Amazon Redshift で、ディスクの使用率が高くなるか、容量の上限に達してしまいます。ディスク使用率が高くなる問題のトラブルシューティング方法を教えてください。

解決方法

ディスク使用率が高いエラーは、次のような要因によって変わります。

  • 分散キーとソートキー
  • クエリ処理
  • VARCHAR (MAX) 列を含むテーブル
  • 列の高圧縮
  • メンテナンスオペレーション
  • クロス結合を持つデカルト積
  • 最小テーブルサイズ
  • 廃棄ブロック
  • 大きなファイルのコピー

分散キーとソートキー

テーブルの分散スタイル、分散キー、ソートキーの選択を確認します。ディスクノードがいっぱいになるのは、分散スキューがあるテーブルで、1 つのノード内に他のノードよりも多くのデータがあることが原因となる可能性があります。偏った分散スタイルを持つテーブルがある場合は、より均一な分散に分散スタイルを変更します。分散と行スキューは、クエリの実行中に、ストレージスキューと中間行セットに影響を与える可能性があることに注意してください。分散キーとソートキーの詳細については、Amazon Redshift engineering’s advanced table design playbook: preamble, prerequisites, and prioritizationを参照してください。

次のクエリを実行し、分散キーの基数を確認します。

select distkey, count(*) from public.distribution_skew group by distkey having count(*) > 1 order by 2 desc;

注: ソート手順を回避するには、ORDER BY 句で SORT KEY 列を使用します。ソート手順でメモリが過剰に使用されると、ディスクがあふれることがあります。詳細については、ソートキーの選択、を参照してください。

分散キーのデータベースブロックがクラスターにマップされる方法を確認するには、Amazon Redshift table_inspector.sql ユーティリティを使用します。

クエリ処理

クエリに割り当てられているメモリを確認します。クエリの処理中に、クエリの中間結果が一時ブロックに保存される場合があります。十分な空きメモリがない場合、テーブルはディスクに書き込まれてディスクを圧迫します。中間的な結果セットは圧縮されないため、使用可能なディスク容量に影響します。詳細については、クエリに割り当てられてメモリが不十分、を参照してください。

Amazon Redshift のデフォルトは、均等な分散のテーブル構造であり、一時テーブル用に列エンコードは行いません。ただし、SELECT ... INTO 構文を使用している場合は、CREATE ステートメント含めることができます。詳細については、Top 10 performance tuning techniques for Amazon Redshift を参照し、Tip #6: Address the inefficient use of temporary tables の手順に従ってください。

クエリに十分なメモリが割り当てられていない場合、is_diskbased が "true" である SVL_QUERY_SUMMARY 内のステップを確認してみてください。この問題を解決するには、クエリスロットの数を増やして、クエリにより多くのメモリを割り当てます。クエリのスロットを一時的に増やす方法の詳細については、wlm_query_slot_count を参照するか、WLM を調整して混合ワークロードを実行します。また、WLM クエリモニタリングルールを使用すると、入出力の多いクエリを識別しながら、大量の処理負荷に対処することもできます。

VARCHAR (MAX) 列を含むテーブル

VARCHAR または CHARACTER VARYING 列で、データをディスクに格納する際に省略できる空白が、末尾に付加されていないか確認します。末尾の空白は、クエリ処理中メモリ内の全長 (VARCHAR の最大値は 65535) を占める可能性があります。可能な限り最小の列サイズを使用することがベストプラクティスです。

最大列幅を持つテーブルのリストを生成するには、次のクエリを実行します。

SELECT database, schema || '.' || "table" AS "table", max_varchar FROM svv_table_info WHERE max_varchar > 150 ORDER BY 2;

幅広い VARCHAR テーブルの列について、真の幅を識別して表示するには、次のクエリを実行します。

SELECT max(octet_length (rtrim(column_name))) FROM table_name;

テーブル設計の詳細については、Amazon Redshift best practices for designing tables、を参照してください。

列の高圧縮

列を最適にエンコードするために、ANALYZE COMPRESSION または Amazon Redshift Column Encoding Utility を、すべての列(ソートキーを除く) のエンコードに使用します。Amazon Redshift には、ストレージ全体の消費量を削減しながら、読み取りパフォーマンスを向上できる、列エンコード機能があります。ベストプラクティスとしては、システム圧縮機能を使用します。

メンテナンスオペレーション

Amazon Redshift データベースのデータベーステーブルが定期的に分析され、バキューム処理されていることを確認します。データベースの状態を維持する 1 つの方法は、不足している統計または古い統計を特定することです。これにより、Amazon Redshift が不要なテーブル行をスキャンするのを防ぎ、クエリ処理の最適化にも役立ちます。

注: VACUUM や DEEP COPY などの保守オペレーションでは、ソートオペレーションにより一時ストレージ領域が使用されるため、ディスク使用量が一時的に急増することが予想されます。

たとえば、次のクエリは、Amazon Redshift にある古くなった統計を特定するのに役立ちます。

SELECT * FROM svv_table_info WHERE stats_off > 10 ORDER BY size DESC;

詳細については、Amazon Redshift Analyze & Vacuum Schema Utility を参照してください。

クロス結合を持つデカルト積

デカルト積を含むクエリを検索するには、クエリの EXPLAIN プランを使用します。デカルト積は、関係性のないクロス結合なので、ブロック数を増やす可能性があります。このクロス結合により、メモリ使用率が高くなり、ディスクに書き込まれるテーブルが増える可能性があります。クロス結合が JOIN 条件を共有していない場合、結合は 2 つのテーブルのデカルト積を生成します。この場合、1 つのテーブルのすべての行が、もう 1 つのテーブルのすべての行に結合されます。

クロス結合は、ネストされたループ結合として実行されることもあり、処理に最も時間がかかります。ネストされたループ結合により、全体的なディスク使用量が急増します。詳細については、ネステッドループにあるクエリの特定、を参照してください。

最小テーブルサイズ

同じテーブルでも、クラスターによってテーブルサイズが異なる場合があります。次に、最小テーブルサイズは、列の数と、テーブルに SORTKEY があるか、およびスライスの数が入力されているかどうかによって決まります。最近 Amazon Redshift クラスターのサイズを変更した場合、ディスクストレージ全体に変化が見られる可能性があります。これはスライス数が変化したことが原因です。Amazon Redshift は、各テーブルで使用されるテーブルセグメントもカウントします。詳細については、Amazon Redshift クラスターのテーブルが想定と異なるディスクストレージを消費していますが、なぜですか?、を参照してください。

廃棄ブロック

廃棄ブロックは、Amazon Redshift テーブルへの WRITE トランザクションが発生し、同時に読み取りも実行されている場合に生成されます。Amazon Redshift は、書き込みオペレーションの前にブロックを保持して、同時読み取りオペレーションの一貫性を保ちます。Amazon Redshift ブロックは変更できません。InsertUpdate、または Delete の各アクションは、新しいブロックのセットを作成し、古いブロックを廃棄済みとしてマークします。

テーブルのトランザクションが長時間実行されることが原因で、廃棄ブロックがコミット段階でクリアされないことがあります。廃棄ブロックは、同時に実行されている ETL ロードが多すぎる場合にもクリアに失敗することがあります。Amazon Redshift はトランザクションの開始時点からデータベースをモニタリングするため、データベースに書き込まれたテーブルにも廃棄ブロックが保持されます。長時間実行されるテーブルトランザクションが、定期的かつ複数のロードにわたって発生した場合、廃棄ブロックが蓄積されて、ディスクがいっぱいになるエラーが発生する可能性があります。

commit コマンドを実行して、Amazon Redshift に廃棄ブロックに関する分析を強制的に実行させることもできます。

アクティブな実行時間の長いクエリがある場合は、commit コマンドを使用して、クエリを終了(および後続のすべてのブロックを解放)します。

begin;
create table a (id int);
insert into a values(1);
commit;
drop table a;

廃棄ブロックを確認するには、次のクエリを実行します。

select trim(name) as tablename, count(case when tombstone > 0 then 1 else null end) as tombstones from svv_diskusage group by 1 having count(case when tombstone > 0 then 1 else null end) > 0 order by 2 desc;

大きなファイルのコピー

COPY オペレーション中に、十分なストレージが利用可能であっても、Disk Full (ディスクがいっぱいです) エラーが発生する可能性があります。このエラーは、ソートオペレーションがディスクに書き出され、一時ブロックが作成される場合に発生します。

Disk Full エラーメッセージが表示された場合は、STL_DISK_FULL_DIAG テーブルを確認します。

select '2000-01-01'::timestamp + (currenttime/1000000.0)* interval '1 second' as currenttime,node_num,query_id,temp_blocks from pg_catalog.stl_disk_full_diag;

その他のベストプラクティスについては、Amazon Redshift best practices for loading data、を参照してください。

追加のトラブルシューティング

Amazon Redshift コンソール の [パフォーマンス] タブで、デイスクの資料率を確認します。各クラスターノードに対して、Amazon Redshift は追加のディスクスペースを提供します。これは、名目上のディスク容量よりも大きくなります。

使用率の急激なスパイクに気付いた場合は、 STL_QUERY を使用して、実行中のアクティビティとジョブを特定します。

select * from stl_query where starttime between '2018-01-01 00:30:00' and '2018-01-01 00:40:00';

注: スパイクが発生した時刻で値を更新します。

上位 20 のディスクスピルクエリを特定するには、次のクエリを実行します。

select A.userid, A.query, blocks_to_disk, trim(B.querytxt) text from stl_query_metrics A, stl_query B where A.query = B.query and segment=-1 and step = -1 and max_blocks_to_disk > 0 order by 3 desc limit 20;

クエリがディスクに正しく書き込んでいるかどうかを確認するには、次のクエリを実行します。

SELECT q.query, trim(q.cat_text)
FROM (
SELECT query,
replace( listagg(text,' ') WITHIN GROUP (ORDER BY sequence), '\\n', ' ') AS cat_text
FROM stl_querytext
WHERE userid>1
GROUP BY query) q
JOIN (
SELECT distinct query
FROM svl_query_summary
WHERE is_diskbased='t' AND (LABEL ILIKE 'hash%' OR LABEL ILIKE 'sort%' OR LABEL ILIKE 'aggr%' OR LABEL ILIKE 'save%' OR LABEL ILIKE 'window%' OR LABEL ILIKE 'unique%')
AND userid > 1) qs
ON qs.query = q.query;

この記事はお役に立ちましたか?


請求に関するサポートまたは技術サポートが必要ですか?