Pivotal Knowledge Base

フォローする

FAQ - HEAP テーブルの肥大化について

目的

場合によっては、基盤となるストレージアーキテクチャーのために、Greenplum は "HEAP" テーブルの肥大化という影響を受けやすい。当該テーブルの肥大化は、テーブルスキャンのパフォーマンスに影響を与える可能性があり、その結果、クエリーのパフォーマンスにも影響を与えかねない。

本記事では、以下の内容を取り上げる。

  1. テーブルの肥大化とは?
  2. なぜテーブルの肥大化が発生するのか?
  3. テーブルの肥大化の確認方法
  4. テーブルの肥大化を除去する方法
  5. 推奨事項

回答

1. テーブルの肥大化とは?

テーブルの肥大化は、テーブルデータファイル内の古いデータ行によって使用された空き領域が蓄積したものである。この領域は、以前に削除され、もうすでにアクセス不能なデータ行によって使用されていたものである。この領域を再利用するためのテーブルメンテナンスに失敗すると、テーブルデータファイルのサイズがさらに肥大化し、結果としてテーブルスキャンに時間がかかるようになる。

2. なぜテーブルの肥大化が発生するのか?

Greenplum のストレージ実装は、Postgres の実装を適用している(MVCC - MultiVersion Concurrency Control - として知られている)。この実装によると、以下の特徴がある。

インプレース(既存データの直接書き換え)の update は存在しない(update は delete と insert との組み合わせとして実装されている)。行データは、いかなるトランザクションも潜在的に当該データにアクセスしないことが確定した後、VACUUM コマンドを通して "空き" 領域と認定されるまで、データファイルに存在し続ける。

一度、VACUUM が削除された行領域を "空き領域" として登録すると、当該領域はその後の insert や update によって再利用することができる。行が削除された後(そしていかなるトランザクションも当該行にアクセスしていない状態)であっても、VACUUM が実行される前は、当該領域は再利用される空き領域として認定されておらず、実質的に "デッドスペース" となっている。

3. テーブルの肥大化の確認方法

gp_toolkit 管理スキーマを活用する。

gp_toolkit.gp_bloat_diag - このビューは、中程度あるいは深刻な肥大化が発生しているテーブルを表示する。

列名:

  • bdirelid - テーブルのオブジェクト ID(pg_class.oid)
  • bdinspname - テーブルスキーマ名
  • bdirelname - テーブル名
  • bdirelpages - テーブルデータファイルにおける現在のページ数
  • bdiexppages - 現在の統計値による期待されるページ数
  • bdidiag - テーブル肥大化状況の分析(割合が 1〜3 →肥大化なし、割合が 4〜10 →中程度の肥大化、割合が 10 を超えている→深刻な肥大化が発生)

例:

この例では、テーブル "t1" が極端に肥大化しているといえる(計算上のデータサイズは現在 1 ページ分であるのに、実際には 97 ページで構成されている)。

gpadmin=# select * from gp_toolkit.gp_bloat_diag;
 bdirelid | bdinspname | bdirelname | bdirelpages | bdiexppages |                bdidiag                
----------+------------+------------+-------------+-------------+---------------------------------------
    21488 | public     | t1         |          97 |           1 | significant amount of bloat suspected
(1 row)

gp_toolkit.gp_bloat_expected_pages - このビューは、データベース列における全てのテーブルのページデータ(現在のページ数・期待されるページ数)を表示する。

  • btdrelid - テーブルのオブジェクト ID(pg_class.oid)
  • btdrelpages - テーブルデータファイルにおける現在のページ数
  • btdexppages -現在の統計値による期待されるページ数

例: この例では、表示されている全てのテーブルでデータサイズが 1 ページで、実際のデーターサイズも 1 ページと計算されている。従って、テーブルの肥大化は認められない。

gpadmin=# select * from gp_toolkit.gp_bloat_expected_pages limit 5;
 btdrelid | btdrelpages | btdexppages 
----------+-------------+-------------
    10789 |           1 |           1
    10794 |           1 |           1
    10799 |           1 |           1
     5004 |           1 |           1
     7175 |           1 |           1
(5 rows)

注意

  • これらのビューは、テーブルの肥大化度合いを掲載するため、テーブルの統計値に依存している。従って、テーブル統計値が最新の状態であることは非常に重要である!
  • Pivotal Greenplum データベースシステムテーブルは "HEAP" テーブルである。従って、それらはテーブル肥大化の影響を受けやすい。システムテーブルは、データベースのパフォーマンスを維持するために非常に重要なので、定期的な VACUUM の実行が推奨される。推奨される実行間隔は、オブジェクトの変更(create/drop/alter table)がほとんどなければ 1 週間おきから、多い場合は 1 日おきあるいはより短い期間まで様々である。

4. テーブルの肥大化を除去する方法

VACUUM コマンドは、再利用可能な "空きスペース" を確保できるよう、テーブルの削除された行にマーキングを行うために使用され、結果、テーブル肥大化を除去する。多くの UPDATE/DELETE/INSERT といったワークロードを伴うテーブルが、新規データ投入時に再利用されるであろう削除された行と空き領域を若干量保持することは普通であり、健全な状態である。VACUUM の定期実行は、削除された行が空き領域としてできるだけ早く再利用されることを保証するものである。

ある事例では、VACUUM が長時間動作せず、データファイルに大量の削除された行(dead rows)が蓄積されている一方、実テーブル行は少量のテーブルデータファイルから構成されるような状況となることがある(言い換えれば、テーブルは著しく肥大化している)。このような場合、余計に確保された領域を除去するために(もし当該領域が結果として再利用されないとしても)、VACUUM FULL コマンドの実行が想定される。このコマンドは、データファイルの先頭にテーブルデータを移動することでデータ圧縮を行い、後尾の未使用領域を切り捨てる。

VACUUM FULL は、行を 1 つずつ圧縮していくため、サイズの大きいテーブルに対しては実行速度が遅くなる上、当該テーブルに対して排他的ロックをかける。
VACUUM FULL の実行は、メンテナンスウィンドウに基づき、実行時間と影響について注意深く考慮した上で行うことが推奨される。
VACUUM FULL コマンドは、一度実行されたら、ユーザーによる停止は行うべきではない。

ユーザーテーブルに対する VACUUM FULL のより良い代替手段は、テーブルの再配置である(ただし、システムテーブルに対しては実行不可)。この方法は、実行中に、テーブルの肥大化を除去しながら効果的にテーブルの再構築を行う。

以下手順を示す。

  • 各テーブルの分散配置列を確認。
  • ALTER TABLE SET with (REORGANIZE=false) DISTRIBUTED randomly; の実行 -- 各テーブルに "マーキング" するだけで、列自体の移動はない。従って、すぐに実行完了する。
  • ALTER TABLE SET with (REORGANIZE=true) DISTRIBUTED BY (<列名>); の実行 -- データファイルの再書き込みを実施。分散配置自体では実際にはデータファイルレベルでの変更は伴わないので、ネットワーク越しに列データを送信せずにローカル環境で再書き込みが実施される。

データベースの肥大化を除去するためのさらなるオプションについてはこちらの記事を参照のこと。

注意

  • VACUUM FULL とテーブル再配置を用いたより良い代替手段については、肥大化が極端な場合にのみ推奨される。
  • VACUUM は、INSERT/UPDATE/DELETE といったワークロードが伴うテーブルと、システムテーブルに対して定期的に実行することが推奨される。

5. 推奨事項

  • gp_toolkit のビューによる、システムテーブルとユーザーテーブルにおけるテーブル肥大化確認の定期実施。
  • 定期的なシステムテーブルに対する VACUUM の実施(オブジェクトの create/drop/alter の実行頻度による)。
  • 多くの INSERT/UPDATE/DELETE といった処理を伴うユーザーテーブルを識別し、当該処理の頻度が少ない場合か、テーブル肥大化の蓄積に応じて当該処理を行わないタイムウィンドウを設けて VACUUM を実施。

コメント

Powered by Zendesk