REINDEX — インデックスを再構築する
REINDEX [ (option[, ...] ) ] { INDEX | TABLE | SCHEMA | DATABASE | SYSTEM } [ CONCURRENTLY ]nameここでoptionは以下の一つです。 CONCURRENTLY [boolean] TABLESPACEnew_tablespaceVERBOSE [boolean]
REINDEXは、インデックスのテーブルに保存されたデータを使用してインデックスを再構築し、古いインデックスのコピーと置き換えます。
以下にREINDEXが使用される状況を示します。
インデックスが破損してしまい、有効なデータがなくなった場合です。
理論的には決して起こらないはずですが、実際には、ソフトウェアのバグやハードウェアの障害によりインデックスが破損することがあります。
REINDEXはこの修復手段を提供します。
インデックスが「膨張状態」、つまり、多くの空、もしくは、ほとんど空のページを持つ状態になっている場合です。
この状況は、PostgreSQLのB-treeインデックスが特定の普通でないパターンでアクセスされた場合に起こり得ます。
REINDEXを使って、使用されないページを取り除いた新しいインデックス作成すると、インデックスの領域消費量を減少することができます。
詳細は25.2を参照してください。
インデックスの格納パラメータ(フィルファクタなど)を変更し、この変更を確実に有効にしたい場合です。
CONCURRENTLYオプションをつけたインデックス作成が失敗すると、このインデックスは「無効」として残されます。
こうしたインデックスは使用されませんが、REINDEXを使用して再作成するのが便利かもしれません。
REINDEX INDEXだけが無効なインデックスでの同時構築を実行できることに注意してください。
INDEX
指定したインデックスを再作成します。
この構文のREINDEXは、パーティションインデックスと使われる場合にはトランザクションブロック内で実行できません。
TABLE
指定したテーブルの全インデックスを再作成します。
テーブルに2次的な「TOAST」テーブルがある場合、それについてもインデックスを再作成します。
この構文のREINDEXは、パーティションテーブルと使われる場合にはトランザクションブロック内で実行できません。
SCHEMA
指定したスキーマのすべてのインデックスを再作成します。
このスキーマのテーブルが二次的な「TOAST」テーブルを持っている場合は、そのインデックスも再作成されます。
共有システムカタログのインデックスも処理されます。
この構文のREINDEXはトランザクションブロック内で実行できません。
DATABASE
現在のデータベースのすべてのインデックスを再作成します。
共有システムカタログのインデックスも処理されます。
この構文のREINDEXをトランザクションブロック内で実行できません。
SYSTEM
現在のデータベースのシステムカタログに対するすべてのインデックスを再作成します。
共有システムカタログのインデックスも含みます。
ユーザテーブルのインデックスは処理されません。
この構文のREINDEXをトランザクションブロック内で実行できません。
name
インデックスを再作成するインデックス、テーブル、データベースの名前です。
インデックスとテーブルはスキーマ修飾可能です。
現状では、REINDEX DATABASEとREINDEX SYSTEMは現在のデータベースのインデックスのみを再作成することができます。
そのため、このパラメータは現在のデータベース名と一致する必要があります。
CONCURRENTLYこのオプションが使われると、PostgreSQLは、そのテーブルで同時実行される挿入、更新、削除を妨げるようなロックを取得せずにインデックスを再構築します。一方、標準のインデックス再構築は終了するまでテーブルの書き込みをロックします(読み込みはロックしません)。 このオプションを使用する場合に注意すべき点がいくつかあります—下記のRebuilding Indexes Concurrentlyを参照してください。
一時テーブルに対してはREINDEXは常に同時再作成ではありません。他のセッションはアクセスできませんし、同時でないインデックス再作成の方がより安価だからです。
TABLESPACE新しいテーブル空間でインデックスを再構築することを指定します。
VERBOSE各インデックスが再作成されるときに、進捗レポートを表示します。
boolean
選択したオプションをオンにするかオフにするか指定します。
オプションを有効にするにはTRUE、ONまたは1と、無効にするにはFALSE、OFFまたは0と書くことができます。
boolean値は省略することもでき、その場合にはTRUEと仮定されます。
new_tablespaceインデックスが再構築されるテーブル空間です。
ユーザテーブル上の特定のインデックスに破損の疑いがある場合、REINDEX INDEXを使ってそのインデックスを再構築することもできますし、REINDEX TABLEを使ってそのテーブルのすべてのインデックスを再構築することもできます。
システムテーブルのインデックスの破損を復旧する場合の手順はより複雑になります。
この場合、システムによって破損の可能性があるインデックス自体が使用されないようにすることが重要です
(実際は、このようなケースでは、破損したインデックスに依存していたため、サーバプロセスが起動時に強制終了してしまう可能性があります)。
安全に復旧させるには、システムカタログ検索時のインデックスの使用を禁止する-Pオプションを使用してサーバを起動しなければなりません。
考えられる方法の1つは次の方法です。まず、サーバを停止して、コマンドラインから-Pオプションを指定してシングルユーザ状態のPostgreSQLサーバを起動します。
そして、再構成する範囲に応じて、REINDEX DATABASE、REINDEX SYSTEM、REINDEX TABLE、または、REINDEX INDEXコマンドを発行します。
範囲が不明な場合は、REINDEX SYSTEMを使用して、そのデータベースの全てのシステムインデックスを再構成してください。
その後、シングルユーザ状態のサーバセッションを停止して、通常のサーバを再起動します。
シングルユーザ状態のサーバインタフェースの操作方法についての詳細は、postgresマニュアルページを参照してください。
その他、コマンドラインで-Pを指定して通常のサーバセッションを起動することもできます。
具体的な方法は、クライアントによって異なります。
しかし、libpqベースのクライアントであれば、クライアントを起動する前に環境変数PGOPTIONSを-Pに設定すれば実現できます。
この方法では他のクライアントを締め出す必要はありませんが、修復が終わるまで破損したデータベースへの他のユーザの接続を防止する方が良いことに注意してください。
REINDEXは、インデックスの中身を1から作り直すという点では、インデックスを削除してから再作成する処理と似ています。
しかし、ロックに関しては異なります。
REINDEXはインデックスの元となるテーブルの書き込みをロックしますが、読み込みはロックしません。
また、処理中のインデックスに対するACCESS EXCLUSIVEロックを取得するので、そのインデックスを使用する読み込みはブロックされます。
一方、DROP INDEXは瞬間的に元となるテーブルのACCESS EXCLUSIVEロックを取得するので、書き込みも読み込みもブロックされます。
その後に行うCREATE INDEXでは書き込みのみをロックし、読み込みはロックしません。
インデックスは存在しないので、インデックスを使用する読み込みは発生しません。
したがって、読み込みがブロックされることはありませんが、コストが高いシーケンシャルスキャンの使用を強制されることになるかもしれません。
単一インデックスまたは単一テーブルのインデックス再作成を行うには、そのインデックスまたはテーブルの所有者でなければなりません。
スキーマまたはデータベースに対するインデックス再作成を行うには、そのスキーマまたはデータベースの所有者でなければなりません。
したがって、非スーパーユーザが他のユーザが所有するテーブルのインデックスを再作成できることに特に注意してください。
しかし、特別な例外として、REINDEX DATABASE、REINDEX SCHEMA、REINDEX SYSTEMが非スーパーユーザにより発行された時には、そのユーザがカタログを所有している場合(そのようなことは通常はありません)を除いて、共有カタログのインデックスは飛ばされます。
もちろん、スーパーユーザは常にすべてのインデックス再作成を行うことができます。
パーティションインデックスやパーティションテーブルのインデックス再作成は、それぞれREINDEX INDEX、REINDEX TABLEでサポートされています。
指定されたパーティションリレーションの個々のパーティションが、別々のトランザクションでインデックスを再作成されます。
パーティションテーブルやパーティションインデックスに対して操作する場合、このコマンドをトランザクションブロック内では使えません。
パーティションインデックスやパーティションテーブルでTABLESPACE句を使ってREINDEXを行なう場合、リーフパーティションのテーブル空間参照のみが更新されます。
パーティションインデックスは更新されませんので、アタッチされた新しいパーティションが新しいテーブル空間を継承するように、それぞれALTER TABLE ONLYを使うことをお勧めします。
失敗した場合、インデックスはすべて新しいテーブル空間へと移動したわけではないかもしれません。
コマンドを再実行すればリーフパーティションはすべて再構築され、先ほどは処理されなかったインデックスが新しいテーブル空間へと移動します。
SCHEMA、DATABASE、SYSTEMがTABLESPACEと一緒に使われた場合、システムリレーションは飛ばされ、WARNINGが1度出ます。
TOASTテーブルのインデックスは再構築されますが、新しいテーブル空間には移動しません。
インデックスの再構築は、通常のデータベース操作を妨げることがあります。 通常、PostgreSQLはインデックスが再構築されるテーブルへの書き込みをロックし、一度のテーブル走査で全インデックスの構築を実行します。 他のトランザクションはテーブルを読み込めますが、そのテーブルで行を挿入、更新、削除しようとするとインデックスの再構築が終わるまでブロックされます。 実行中の運用状態のデータベースシステムの場合、これは重大な影響を与えるかもしれません。 非常に大規模なテーブルに対するインデックス作成は何時間もかかることがあり得ます。また小規模なテーブルであっても、インデックス再構築により、運用状態のシステムとしては受け入れられないほど長い時間、書き込みロックがかかる可能性があります。
PostgreSQLは最小限の書き込みロックでのインデックス再構築をサポートしています。
REINDEXにCONCURRENTLYオプションをつけることでこの方式が行われます。
このオプションを使うと、PostgreSQLは再構築が必要な各インデックスに関してテーブルを2回走査しなければなりません。さらに、潜在的にそのインデックスを使用する可能性がある、実行中のすべてのトランザクションが終わるまで待機しなければなりません。
したがって、この方式は通常のインデックス再構築よりも総作業時間がかかり、また、インデックスを修正する可能性のある終了していないトランザクションが待つ必要がありますので、完了するまでの時間が非常に長くなります。
しかし、インデックス再構築中に通常の操作を続けることができますので、この方式は運用環境でのインデックス再構築に有用です。
もちろん、インデックス再構築によりCPUやメモリ、入出力に余分に負荷がかかりますので、他の操作が低速になる可能性があります。
同時実行再インデックスは以下のような段階で行なわれます。 各段階は分離したトランザクション内で実行されます。 複数のインデックスを再構築する場合、次の段階に移る前にすべてのインデックスに対して各段階が繰り返されます。
カタログpg_indexに新しく一時的なインデックス定義が追加されます。
この定義は古いインデックスを置き換えるのに使われます。
処理中は、再インデックスされるインデックスと関連するテーブルに対して、セッションレベルでのSHARE UPDATE EXCLUSIVEロックを取得します。スキーマが修正されないようにするためです。
インデックス構築の第1段階は新しいインデックスそれぞれに対して行なわれます。
インデックスが一度構築されれば、挿入の準備ができたということで、そのフラグpg_index.indisreadyは「true」に切り替わります。構築を実行したトランザクションが終わった後で、他のセッションから見えるようになります。
この過程は各インデックスに対して分離したトランザクションで行なわれます。
次に、第1段階実行中に追加されたタプルを追加する第2段階が行なわれます。 この過程は各インデックスに対して分離したトランザクションで行なわれます。
インデックスを参照する制約は、すべて新しいインデックス定義を参照するよう変更され、インデックスの名前が変更されます。
この時点で、pg_index.indisvalidは新しいインデックスに対しては「true」に切り替えられ、古いものに対しては「false」に切り替えられます。そして、古いインデックスを参照するセッションをすべて無効にするためキャッシュの無効化が行なわれます。
古いインデックスを参照している可能性のある実行中の問い合わせが完了するのをまってから、新しいタプルが挿入されないように古いインデックスはpg_index.indisreadyが「false」に切り替えられます。
古いインデックスが削除されます。
インデックスやテーブルに対するSHARE UPDATE EXCLUSIVEセッションロックは解放されます。
インデックスの再構築中に、一意性インデックスでの一意性違反などの問題が発生したら、REINDEXコマンドは失敗しますが、既に存在しているものに加えて「無効な」新しいインデックスを残します。
このインデックスは不完全な可能性がありますので、問い合わせの目的では無視されます。しかし、更新のオーバーヘッドは消費し続けるでしょう。
psql \dコマンドはそのようなインデックスをINVALIDと報告します。
postgres=# \d tab
Table "public.tab"
Column | Type | Modifiers
--------+---------+-----------
col | integer |
Indexes:
"idx" btree (col)
"idx_ccnew" btree (col) INVALID
INVALIDと印づけられたインデックスに接尾辞ccnewがついている場合、それは同時実行操作中に作られた一時的なインデックスに対応します。お勧めの回復法はDROP INDEXを使ってそれを削除して、再度REINDEX CONCURRENTLYを試みることです。
無効なインデックスにその代わりに接尾辞ccoldがついている場合、それは削除できなかった元のインデックスに対応します。
正式な再構築は成功していますので、お勧めの回復法は単に前記のインデックスを削除することです。
通常のインデックス構築は、同じテーブルでの他の通常のインデックス構築を許しますが、同時実行インデックス構築は1つだけが一度に1つのテーブルでできます。
どちらの場合でも、その間のそのテーブルでの他の種類のスキーマ修正は認められていません。
もう一つの違いは、通常のREINDEX TABLEやREINDEX INDEXコマンドはトランザクションブロックの内側で実行できますが、REINDEX CONCURRENTLYはできないことです。
他の時間のかかるトランザクションと同じく、あるテーブルに対するREINDEXは、その他のテーブルに対する同時実行中のVACUUMによりどのタプルが削除できるかに影響します。
システムカタログは同時実行で再インデックスできませんので、REINDEX SYSTEMはCONCURRENTLYをサポートしません。
さらに、排他制約に対するインデックスは同時実行で再インデックスできません。
このコマンドでそのようなインデックスの名前が直接指定されたら、エラーが起きます。
排他制約インデックスのあるテーブルやテータベースが同時実行で再インデックスされる場合、そのインデックスは飛ばされます。
(そのようなインデックスをCONCURRENTLYオプションなしで再インデックスすることは可能です。)
REINDEXを実行している各バックエンドはその進捗をpg_stat_progress_create_indexビューで報告します。
詳細は28.4.2を参照してください。
単一のインデックスを再構築します。
REINDEX INDEX my_index;
テーブルmy_table上のすべてのインデックスを再構築します。
REINDEX TABLE my_table;
システムインデックスが有効かどうかを確認することなく、あるデータベース内の全てのインデックスを再構築します。
$export PGOPTIONS="-P"$psql broken_db... broken_db=> REINDEX DATABASE broken_db; broken_db=> \q
再インデックスの進行中に、関連するリレーションの読み書きをブロックすることなく、テーブルに対するインデックスを再構築します。
REINDEX TABLE CONCURRENTLY my_broken_table;
標準SQLにはREINDEXはありません。