# 重新索引

REINDEX — 重建索引

# 概要

REINDEX [ ( option [, ...] ) ] { INDEX | TABLE | SCHEMA | DATABASE | SYSTEM } [ CONCURRENTLY ] name

where option can be one of:

    CONCURRENTLY [ boolean ]
    TABLESPACE new_tablespace
    VERBOSE [ boolean ]

# 描述

重新索引使用存储在索引表中的数据重建索引,替换索引的旧副本。有几种使用场景重新索引

  • 索引已损坏,不再包含有效数据。虽然理论上这不应该发生,但实际上索引可能由于软件错误或硬件故障而损坏。重新索引提供了一种恢复方法。

  • 索引变得“臃肿”,即它包含许多空页面或几乎空页面。在某些不常见的访问模式下,PostgreSQL 中的 B-tree 索引可能会发生这种情况。重新索引提供了一种通过编写没有死页的新版本索引来减少索引空间消耗的方法。看第 25.2 节了解更多信息。

  • 您已更改索引的存储参数(例如填充因子),并希望确保更改已完全生效。

  • 如果索引构建失败同时选项,此索引保留为“无效”。这样的索引没用但是用起来很方便重新索引重建它们。请注意,仅REINDEX 指数能够在无效索引上执行并发构建。

# 参数

指数

重新创建指定的索引。这种形式的重新索引与分区索引一起使用时,不能在事务块内执行。

桌子

重新创建指定表的所有索引。如果该表有一个辅助“TOAST”表,那么它也会被重新索引。这种形式的重新索引与分区表一起使用时,不能在事务块内执行。

架构

重新创建指定架构的所有索引。如果此模式的表具有辅助“TOAST”表,则该表也将被重新索引。共享系统目录上的索引也会被处理。这种形式的重新索引不能在事务块内执行。

数据库

重新创建当前数据库中的所有索引。共享系统目录上的索引也会被处理。这种形式的重新索引不能在事务块内执行。

系统

重新创建当前数据库中系统目录的所有索引。包括共享系统目录的索引。不处理用户表上的索引。这种形式的重新索引不能在事务块内执行。

姓名

要重新编制索引的特定索引、表或数据库的名称。索引和表名可以是模式限定的。目前,重新索引数据库重新索引系统只能重新索引当前数据库,因此它们的参数必须与当前数据库的名称匹配。

同时

当使用此选项时,PostgreSQL 将重建索引而不使用任何阻止对表进行并发插入、更新或删除的锁;而标准索引重建会锁定表上的写入(但不读取),直到完成为止。使用此选项时需要注意几个注意事项 - 请参阅同时重建索引以下。

对于临时表,重新索引总是非并发的,因为没有其他会话可以访问它们,并且非并发重新索引更便宜。

表空间

指定将在新表空间上重建索引。

详细

在重新索引每个索引时打印进度报告。

布尔值

指定是否应打开或关闭所选选项。你可以写真的,, 要么1启用该选项,并且错误的,离开, 要么0禁用它。这*布尔值*value 也可以省略,在这种情况下真的假设。

新表空间

将重建索引的表空间。

# 笔记

如果您怀疑用户表上的索引损坏,您可以简单地重建该索引或表上的所有索引,使用REINDEX 指数要么重新索引表.

如果您需要从系统表上的索引损坏中恢复,事情会更加困难。在这种情况下,系统本身不使用任何可疑索引很重要。(实际上,在这种情况下,您可能会发现由于依赖损坏的索引,服务器进程在启动时立即崩溃。)为了安全地恢复,服务器必须以-P选项,它阻止它使用索引进行系统目录查找。

一种方法是关闭服务器并使用以下命令启动单用户 PostgreSQL 服务器-P选项包含在其命令行中。然后,重新索引数据库,重新索引系统,重新索引表, 要么REINDEX 指数可以发出,取决于你要重建多少。如有疑问,请使用重新索引系统选择重建数据库中的所有系统索引。然后退出单用户服务器会话并重新启动常规服务器。见postgres参考页面以获取有关如何与单用户服务器界面交互的更多信息。

或者,可以使用以下命令启动常规服务器会话-P包含在其命令行选项中。执行此操作的方法因客户端而异,但在所有基于 libpq 的客户端中,都可以设置选项环境变量为-P在启动客户端之前。请注意,虽然此方法不需要锁定其他客户端,但在修复完成之前阻止其他用户连接到损坏的数据库可能仍然是明智之举。

重新索引类似于索引的删除和重新创建,因为索引内容是从头开始重建的。然而,锁定的考虑是相当不同的。重新索引锁定索引的父表的写入但不读取。它还需要一个访问独家锁定正在处理的特定索引,这将阻止尝试使用该索引的读取。相比之下,删除索引暂时需要一个访问独家锁定父表,阻止写入和读取。随后的创建索引锁定写入但不读取;由于索引不存在,没有读取将尝试使用它,这意味着不会阻塞,但读取可能会被迫进行昂贵的顺序扫描。

重新索引单个索引或表需要成为该索引或表的所有者。重新索引架构或数据库需要成为该架构或数据库的所有者。请特别注意,非超级用户因此可以重建其他用户拥有的表的索引。然而,作为一个特殊的例外,当重新索引数据库,重新索引架构或者重新索引系统由非超级用户发布,共享目录上的索引将被跳过,除非用户拥有该目录(通常情况并非如此)。当然,超级用户总是可以重新索引任何东西。

支持重新索引分区索引或分区表REINDEX 指数或者重新索引表, 分别。指定分区关系的每个分区都在单独的事务中重新索引。在处理分区表或索引时,这些命令不能在事务块内使用。

使用时表空间子句重新索引在分区索引或表上,仅更新叶分区的表空间引用。由于分区索引没有更新,建议单独使用仅更改表在它们上,以便附加的任何新分区继承新表空间。失败时,它可能没有将所有索引移动到新表空间。重新运行该命令将重建所有叶分区并将以前未处理的索引移动到新表空间。

如果架构,数据库要么系统表空间, 系统关系被跳过并且单个警告会生成。TOAST 表上的索引会重建,但不会移动到新表空间。

# 同时重建索引

重建索引可能会干扰数据库的常规操作。通常 PostgreSQL 锁定其索引针对写入重建的表,并通过对表的单次扫描来执行整个索引构建。其他事务仍然可以读取该表,但如果它们尝试在表中插入、更新或删除行,它们将阻塞,直到索引重建完成。如果系统是实时生产数据库,这可能会产生严重影响。对非常大的表进行索引可能需要花费数小时,即使对于较小的表,索引重建也会在生产系统无法接受的长时期内锁定写入者。

PostgreSQL 支持以最少的写入锁定来重建索引。通过指定同时选项重新索引.使用此选项时,PostgreSQL 必须对需要重建的每个索引执行两次表扫描,并等待可能使用该索引的所有现有事务的终止。与标准索引重建相比,此方法需要更多的总工作量,并且需要更长的时间才能完成,因为它需要等待可能修改索引的未完成事务。但是,由于它允许在重建索引时继续正常操作,因此此方法对于在生产环境中重建索引很有用。当然,索引重建带来的额外 CPU、内存和 I/O 负载可能会减慢其他操作。

以下步骤发生在并发重新索引中。每个步骤都在单独的事务中运行。如果有多个索引要重建,则每个步骤都会循环遍历所有索引,然后再进行下一步。

  1. 将新的临时索引定义添加到目录中pg_index.此定义将用于替换旧索引。一种共享更新独家对正在重新索引的索引及其关联表进行会话级别的锁定,以防止在处理过程中进行任何模式修改。

  2. 为每个新索引完成构建索引的第一遍。建立索引后,它的标志pg_index.indisready切换到“true”以使其准备好插入,一旦执行构建的事务完成,其他会话就可以看到它。此步骤在每个索引的单独事务中完成。

  3. 然后执行第二遍以添加在第一遍运行时添加的元组。此步骤也在每个索引的单独事务中完成。

  4. 引用索引的所有约束都更改为引用新的索引定义,并且索引的名称也更改了。在此刻,pg_index.indisvalid将新索引切换为“true”,将旧索引切换为“false”,并完成缓存失效,导致所有引用旧索引的会话失效。

  5. 旧索引有pg_index.indisready在等待可能引用旧索引的运行查询完成后,切换到“false”以防止任何新的元组插入。

  6. 旧索引被删除。这共享更新独家索引和表的会话锁被释放。

    如果在重建索引时出现问题,例如唯一索引中的唯一性违规,则重新索引命令将失败,但除了已有的索引之外,还会留下一个“无效”的新索引。出于查询目的,该索引将被忽略,因为它可能不完整;但是它仍然会消耗更新开销。psql\d命令将报告这样的索引无效的

postgres=# \d tab
       Table "public.tab"
 Column |  Type   | Modifiers
## Examples

 Rebuild a single index:

REINDEX 索引 my_index;

 Rebuild all the indexes on the table `my_table`:

重新索引表 my_table;

 Rebuild all indexes in a particular database, without trusting the system indexes to be valid already:

$ export PGOPTIONS="-P" $ psql broken_db ... broken_db=> REINDEX DATABASE broken_db;破碎数据库=> \q

 Rebuild indexes for a table, without blocking read and write operations on involved relations while reindexing is in progress:

同时重新索引表 my_broken_table;

## Compatibility

 There is no `REINDEX` command in the SQL standard.

## See Also

[CREATE INDEX](sql-createindex.html), [DROP INDEX](sql-dropindex.html), [reindexdb](app-reindexdb.html), [Section 28.4.2](progress-reporting.html#CREATE-INDEX-PROGRESS-REPORTING)