Redshiftのディスクがスペースが予想外に増えたのでVacuumした話

背景

最近分析で使えそうだと思って、個人アカウントでRedshiftを使ってみていろいろ検証してます。

そうすると、運営上、Diskのスペースがどのくらいなのか気になります。

これはWebコンソール上で、Clustersからたどっていきパフォーマンスのタブから確認できます。

Redshift_·_AWS_Console.png

上記は1週間のグラフですがどんどんおおきくなってます。合計50GBくらいになってました。

RedshiftにはMySQLのデータベース内のテーブルをsyncしていれてありますが、MySQLのテーブルの合計は1GBもありません。何が起こったのでしょうか。

問題点

MySQL => Redshiftへのテーブルのsyncをするときに、tmpテーブルを作って、データをいれて、元のテーブルのデータをDELETEで消して、tmpテーブルからインサートしています。syncは1時間ごとです。

SELECT COUNT(*) FROM TABLEとかでみると行数はインサートされた行と同じなのに、以下のコマンドで実行すると何百倍も行数が大きくなってました。

select
  trim(pgdb.datname) as Database,
  trim(pgn.nspname) as Schema,
  trim(a.name) as Table,
  b.mbytes,
  (CAST(b.mbytes as double precision) / 1024) as gbytes,
  (CAST(b.mbytes as double precision) / 1048576) as tbytes,
  a.rows,
  to_char(a.rows, '999,999,999,999,999') as rows_ww,
  to_char(a.rows, '9999,9999,9999,9999') as rows_jp
from (
       select db_id, id, name, sum(rows) as rows
       from stv_tbl_perm a
       group by db_id, id, name
     ) as a
  join pg_class as pgc on pgc.oid = a.id
  join pg_namespace as pgn on pgn.oid = pgc.relnamespace
  join pg_database as pgdb on pgdb.oid = a.db_id
  join (
         select tbl, count(*) as mbytes
         from stv_blocklist
         group by tbl
       ) b on a.id = b.tbl
order by mbytes desc, a.db_id, a.name;

http://dev.classmethod.jp/cloud/aws/amazon-redshift-convenient-sqls/#analyze_table_design_1 から引用

調べてみるとVACUUMの項目に以下の記述が。

行の削除や更新で解放された領域を、Amazon Redshift が自動的に再利用することはありません。更新を実行するために、Amazon Redshift は元の行を削除し、更新された行を追加します。そのため、すべての更新では実質的に削除の後で挿入が行われることになります。削除を実行する場合、行には削除のマークが付けられますが、削除されません。クエリプロセッサは、削除された行と削除されていない行をスキャンする必要があるため、削除された行の数が多すぎると不必要な処理が発生します。大規模な削除や更新の後でバキューム処理を実行することで、領域を再利用してクエリのパフォーマンスを向上させる必要があります。

http://docs.aws.amazon.com/ja_jp/redshift/latest/dg/t_Reclaiming_storage_space202.html から引用

VACUUMが必要でした。以下のように実行してみると、50GBくらいあったものが4GBくらいまで小さくなりました。実行時間は5分ほどだったので、cronで定期的にまわせばいいかなと思ってます。

まとめ

  • 大量のDELETEするときはVACUUMを使ってDiskスペースを確保しよう

ちなみに複数のデータベースを使っている場合は、データベースごとにVACUUMする必要がある。

参考