web-dev-qa-db-ja.com

テーブルのメンテナンス:切り詰めて再入力した後、テーブルをREINDEXする必要がありますか?

分析に使用するトランザクションデータの行が約200万行あるテーブルがあります。毎週、これに新しいデータを再読み込みするため、TRUNCATEを使用してデータをクリアし、新しい行を挿入しています。

テーブルにはいくつかのインデックスがあります。インデックスを削除して再作成しない場合、切り捨てと再入力のたびにインデックスを再作成する必要がありますか、それとも不要ですか? TRUNCATEの後にVACUUMを実行する必要がありますか、それとも不要ですか?

6
JamesF

いいえ、通常、TRUNCATEの後にインデックスを再作成する必要はありません。再作成する場合は、インデックスを削除してデータを読み込み、最後にインデックスを再作成することをお勧めします。

これは クラスターに関するこの回答 に似ています。PgはTRUNCATEの実行中にインデックスを自動的に削除し、データを挿入するたびにインクリメンタルに再構築するため、TRUNCATEの前からインデックスの膨張が発生することはありません。

インデックスを削除し、切り捨ててデータを挿入し、インデックスを再作成すると、インデックスがよりコンパクトで効率的になる場合があります。彼らは確かに構築が速くなります。一度構築されたインデックスのパフォーマンスの違いは、Bツリーインデックスだけを使用するほとんどのアプリケーションの追加の労力を保証するのに十分である可能性は低いですが、テーブルの作成に必要な時間の違いは、それだけの価値があります。 Gistまたは(特に)GINを使用している場合は、インデックスを削除し、最後に再作成するのが最善です。

都合がよい場合は、インデックスを削除して最後に追加し直してください。これが実用的でない場合でも、あまり心配しないでください。

テストでの通常のbツリーの場合、増分的に作成された複合インデックスは3720kbでしたが、1回限り作成されたインデックスは2208kbでした。ビルド時間は164ミリ秒(挿入)+ 347ミリ秒(インデックス)vs 742ミリ秒(挿入+インデックス)でした。この違いは重要ですが、大規模なDWを実行している場合を除いて、大きな懸念にはなりません。 REINDEXは、inserts + indexの実行後、さらに342msかかりました。見る

したがって、@ TomTomは、(当然のことながら)正しい値であるインデックスを削除して再作成することができるという点で適切です(たとえば、 OLAP仕事。

ただし、インデックスの再作成は間違った答えになる可能性があります。これは、大量の負荷のかかる作業を行ってインデックスを作成し、破棄することを意味するためです。インデックスを削除し、インデックスを再作成する代わりに再作成します。

デモセッション:

regress=# -- Create, populate, then create indexes:
regress=# CREATE TABLE demo (someint integer, sometext text);
CREATE TABLE
regress=# \timing on
regress=# INSERT INTO demo (someint, sometext)
SELECT x, (x%100)::text
FROM generate_series(1,100000) x;
INSERT 0 100000
Time: 164.678 ms
regress=# CREATE INDEX composite_idx ON demo(sometext, someint);
CREATE INDEX
Time: 347.958 ms
regress=# SELECT pg_size_pretty(pg_indexes_size('demo'::regclass));
 pg_size_pretty 
----------------
 2208 kB
(1 row)
regress=# -- Total time: 347.958+164.678=512.636ms, index size 2208kB

regress=# -- Now, with truncate and insert:
regress=# TRUNCATE TABLE demo;
TRUNCATE TABLE
regress=# INSERT INTO demo (someint, sometext)
SELECT x, (x%100)::text
FROM generate_series(1,100000) x;
INSERT 0 100000
Time: 742.813 ms
regress=# SELECT pg_size_pretty(pg_indexes_size('demo'::regclass));
 pg_size_pretty 
----------------
 3720 kB
(1 row)
regress=# -- Total time 742ms, index size 3720kB
regress=# -- Difference: about 44% time increase, about 68% index size increase.
regress=# -- Big-ish, but whether you care depends on your application. Now:

regress=# REINDEX INDEX composite_idx ;
REINDEX
Time: 342.283 ms
regress=# SELECT pg_size_pretty(pg_indexes_size('demo'::regclass));
 pg_size_pretty 
----------------
 2208 kB
(1 row)

regress=# -- Index is back to same size, but total time for insert with progressive
regress=# -- index build plus reindex at the end us up to 1084.283, twice as long as
regress=# -- dropping the indexes, inserting the data, and re-creating the indexes took.

そう:

  • OLAPの場合、インデックスの削除、インデックスの挿入、再作成。

  • OLTPの場合は、プログレッシブインデックスビルドを使用することをお勧めします。100%以外のインデックスフィルファクターを考慮して、挿入コストを削減してください。

  • プログレッシブインデックスビルドで挿入してからインデックスを再作成することは避けてください。これは両方の世界で最悪です。

もちろん、このテストで使用されるサイズはおもちゃのテーブルサイズなので、実際のデータとインデックスのサンプルでこのテストを繰り返す必要があります。それがあなたにどの程度の違いをもたらすかについての確固たる考え。上記よりも100大きいスケールファクターでこれらのテストを繰り返したところ、この特定のテストでは相対的なビルド時間の差は実際には下がっていましたが、インクリメンタルにビルドした場合、インデックスはほぼ正確にサイズの2倍でした。

だから:あなたのデータとスキーマでテストします。

3
Craig Ringer