@@ -21,7 +21,7 @@ PostgreSQL documentation
21
21
22
22
<refsynopsisdiv>
23
23
<synopsis>
24
- REINDEX [ ( VERBOSE ) ] { INDEX | TABLE | SCHEMA | DATABASE | SYSTEM } <replaceable class="parameter">name</replaceable>
24
+ REINDEX [ ( VERBOSE ) ] { INDEX | TABLE | SCHEMA | DATABASE | SYSTEM } [ CONCURRENTLY ] <replaceable class="parameter">name</replaceable>
25
25
</synopsis>
26
26
</refsynopsisdiv>
27
27
@@ -68,7 +68,7 @@ REINDEX [ ( VERBOSE ) ] { INDEX | TABLE | SCHEMA | DATABASE | SYSTEM } <replacea
68
68
An index build with the <literal>CONCURRENTLY</literal> option failed, leaving
69
69
an <quote>invalid</quote> index. Such indexes are useless but it can be
70
70
convenient to use <command>REINDEX</command> to rebuild them. Note that
71
- <command>REINDEX</command> will not perform a concurrent build. To build the
71
+ <command>REINDEX</command> will not perform a concurrent build on an invalid index . To build the
72
72
index without interfering with production you should drop the index and
73
73
reissue the <command>CREATE INDEX CONCURRENTLY</command> command.
74
74
</para>
@@ -151,6 +151,21 @@ REINDEX [ ( VERBOSE ) ] { INDEX | TABLE | SCHEMA | DATABASE | SYSTEM } <replacea
151
151
</listitem>
152
152
</varlistentry>
153
153
154
+ <varlistentry>
155
+ <term><literal>CONCURRENTLY</literal></term>
156
+ <listitem>
157
+ <para>
158
+ When this option is used, <productname>PostgreSQL</productname> will rebuild the
159
+ index without taking any locks that prevent concurrent inserts,
160
+ updates, or deletes on the table; whereas a standard reindex build
161
+ locks out writes (but not reads) on the table until it's done.
162
+ There are several caveats to be aware of when using this option
163
+ — see <xref linkend="sql-reindex-concurrently"
164
+ endterm="sql-reindex-concurrently-title"/>.
165
+ </para>
166
+ </listitem>
167
+ </varlistentry>
168
+
154
169
<varlistentry>
155
170
<term><literal>VERBOSE</literal></term>
156
171
<listitem>
@@ -241,6 +256,159 @@ REINDEX [ ( VERBOSE ) ] { INDEX | TABLE | SCHEMA | DATABASE | SYSTEM } <replacea
241
256
Each individual partition can be reindexed separately instead.
242
257
</para>
243
258
259
+ <refsect2 id="sql-reindex-concurrently">
260
+ <title id="sql-reindex-concurrently-title">Rebuilding Indexes Concurrently</title>
261
+
262
+ <indexterm zone="sql-reindex-concurrently">
263
+ <primary>index</primary>
264
+ <secondary>rebuilding concurrently</secondary>
265
+ </indexterm>
266
+
267
+ <para>
268
+ Rebuilding an index can interfere with regular operation of a database.
269
+ Normally <productname>PostgreSQL</productname> locks the table whose index is rebuilt
270
+ against writes and performs the entire index build with a single scan of the
271
+ table. Other transactions can still read the table, but if they try to
272
+ insert, update, or delete rows in the table they will block until the
273
+ index rebuild is finished. This could have a severe effect if the system is
274
+ a live production database. Very large tables can take many hours to be
275
+ indexed, and even for smaller tables, an index rebuild can lock out writers
276
+ for periods that are unacceptably long for a production system.
277
+ </para>
278
+
279
+ <para>
280
+ <productname>PostgreSQL</productname> supports rebuilding indexes with minimum locking
281
+ of writes. This method is invoked by specifying the
282
+ <literal>CONCURRENTLY</literal> option of <command>REINDEX</command>. When this option
283
+ is used, <productname>PostgreSQL</productname> must perform two scans of the table
284
+ for each index that needs to be rebuild and in addition it must wait for
285
+ all existing transactions that could potentially use the index to
286
+ terminate. This method requires more total work than a standard index
287
+ rebuild and takes significantly longer to complete as it needs to wait
288
+ for unfinished transactions that might modify the index. However, since
289
+ it allows normal operations to continue while the index is rebuilt, this
290
+ method is useful for rebuilding indexes in a production environment. Of
291
+ course, the extra CPU, memory and I/O load imposed by the index rebuild
292
+ may slow down other operations.
293
+ </para>
294
+
295
+ <para>
296
+ The following steps occur in a concurrent reindex. Each step is run in a
297
+ separate transaction. If there are multiple indexes to be rebuilt, then
298
+ each step loops through all the indexes before moving to the next step.
299
+
300
+ <orderedlist>
301
+ <listitem>
302
+ <para>
303
+ A new temporary index definition is added into the catalog
304
+ <literal>pg_index</literal>. This definition will be used to replace
305
+ the old index. A <literal>SHARE UPDATE EXCLUSIVE</literal> lock at
306
+ session level is taken on the indexes being reindexed as well as its
307
+ associated table to prevent any schema modification while processing.
308
+ </para>
309
+ </listitem>
310
+
311
+ <listitem>
312
+ <para>
313
+ A first pass to build the index is done for each new index. Once the
314
+ index is built, its flag <literal>pg_index.indisready</literal> is
315
+ switched to <quote>true</quote> to make ready for inserts, making it
316
+ visible to other sessions once the transaction that performed the build
317
+ is finished. This step is done in a separate transaction for each
318
+ index.
319
+ </para>
320
+ </listitem>
321
+
322
+ <listitem>
323
+ <para>
324
+ Then a second pass is performed to add tuples that were added while the
325
+ first pass build was running. This step is also done in a separate
326
+ transaction for each index.
327
+ </para>
328
+ </listitem>
329
+
330
+ <listitem>
331
+ <para>
332
+ All the constraints that refer to the index are changed to refer to the
333
+ new index definition, and the names of the indexes are changed. At
334
+ this point <literal>pg_index.indisvalid</literal> is switched to
335
+ <quote>true</quote> for the new index and to <quote>false</quote> for
336
+ the old, and a cache invalidation is done so as all the sessions that
337
+ referenced the old index are invalidated.
338
+ </para>
339
+ </listitem>
340
+
341
+ <listitem>
342
+ <para>
343
+ The old indexes have <literal>pg_index.indisready</literal> switched to
344
+ <quote>false</quote> to prevent any new tuple insertions, after waiting
345
+ for running queries that might reference the old index to complete.
346
+ </para>
347
+ </listitem>
348
+
349
+ <listitem>
350
+ <para>
351
+ The old indexes are dropped. The <literal>SHARE UPDATE
352
+ EXCLUSIVE</literal> session locks for the indexes and the table ar
353
+ released.
354
+ </para>
355
+ </listitem>
356
+ </orderedlist>
357
+ </para>
358
+
359
+ <para>
360
+ If a problem arises while rebuilding the indexes, such as a
361
+ uniqueness violation in a unique index, the <command>REINDEX</command>
362
+ command will fail but leave behind an <quote>invalid</quote> new index on top
363
+ of the existing one. This index will be ignored for querying purposes
364
+ because it might be incomplete; however it will still consume update
365
+ overhead. The <application>psql</application> <command>\d</command> command will report
366
+ such an index as <literal>INVALID</literal>:
367
+
368
+ <programlisting>
369
+ postgres=# \d tab
370
+ Table "public.tab"
371
+ Column | Type | Modifiers
372
+ --------+---------+-----------
373
+ col | integer |
374
+ Indexes:
375
+ "idx" btree (col)
376
+ "idx_ccnew" btree (col) INVALID
377
+ </programlisting>
378
+
379
+ The recommended recovery method in such cases is to drop the invalid index
380
+ and try again to perform <command>REINDEX CONCURRENTLY</command>. The
381
+ concurrent index created during the processing has a name ending in the
382
+ suffix <literal>ccnew</literal>, or <literal>ccold</literal> if it is an
383
+ old index definition which we failed to drop. Invalid indexes can be
384
+ dropped using <literal>DROP INDEX</literal>, including invalid toast
385
+ indexes.
386
+ </para>
387
+
388
+ <para>
389
+ Regular index builds permit other regular index builds on the same table
390
+ to occur in parallel, but only one concurrent index build can occur on a
391
+ table at a time. In both cases, no other types of schema modification on
392
+ the table are allowed meanwhile. Another difference is that a regular
393
+ <command>REINDEX TABLE</command> or <command>REINDEX INDEX</command>
394
+ command can be performed within a transaction block, but <command>REINDEX
395
+ CONCURRENTLY</command> cannot.
396
+ </para>
397
+
398
+ <para>
399
+ <command>REINDEX SYSTEM</command> does not support
400
+ <command>CONCURRENTLY</command> since system catalogs cannot be reindexed
401
+ concurrently.
402
+ </para>
403
+
404
+ <para>
405
+ Furthermore, indexes for exclusion constraints cannot be reindexed
406
+ concurrently. If such an index is named directly in this command, an
407
+ error is raised. If a table or database with exclusion constraint indexes
408
+ is reindexed concurrently, those indexes will be skipped. (It is possible
409
+ to reindex such indexes without the concurrently option.)
410
+ </para>
411
+ </refsect2>
244
412
</refsect1>
245
413
246
414
<refsect1>
@@ -272,6 +440,14 @@ $ <userinput>psql broken_db</userinput>
272
440
...
273
441
broken_db=> REINDEX DATABASE broken_db;
274
442
broken_db=> \q
443
+ </programlisting></para>
444
+
445
+ <para>
446
+ Rebuild a table while authorizing read and write operations on involved
447
+ relations when performed:
448
+
449
+ <programlisting>
450
+ REINDEX TABLE CONCURRENTLY my_broken_table;
275
451
</programlisting></para>
276
452
</refsect1>
277
453
@@ -282,4 +458,14 @@ broken_db=> \q
282
458
There is no <command>REINDEX</command> command in the SQL standard.
283
459
</para>
284
460
</refsect1>
461
+
462
+ <refsect1>
463
+ <title>See Also</title>
464
+
465
+ <simplelist type="inline">
466
+ <member><xref linkend="sql-createindex"/></member>
467
+ <member><xref linkend="sql-dropindex"/></member>
468
+ <member><xref linkend="app-reindexdb"/></member>
469
+ </simplelist>
470
+ </refsect1>
285
471
</refentry>
0 commit comments