介绍
PostgreSQL 将数据存储在通常具有 8KB 大小的页面上,这意味着当没有足够的空间来存储数据(例如,text 或 varchar 数据类型)时,PostgreSQL 使用 TOAST 技术,该技术允许我们使用其他表,以块的形式存储这些额外的数据,每个块都作为属于主表的 TOAST 表中的单独行存储。用户不需要知道信息是否存储在 TOAST 上。PostgreSQL 透明地将数据传输到那里,并从其中获取数据。当然,并不是我们数据库中的所有表都有 TOAST,要知道哪些表有 TOAST,您可以使用下面的查询:
SELECT
t1.oid,t1.relname, t1.relkind, t1.reltoastrelid, t1.reltoastrelid::regclass
FROM pg_class t1
INNER JOIN pg_class t2
On t1.reltoastrelid = t2.oid
WHERE t1.relkind = 'r' AND t2.relkind = 't';
PostgreSQL 中的数据损坏很少发生,通常出现在一些故障之后,例如磁盘故障、意外断电、硬件故障、使用 fsync=off 配置的数据库系统,或者在较小概率上是由于 PostgreSQL 的问题。比如下面的错误:
ERROR: missing chunk number 0 for toast value XXXXXXX in pg_toast_2619
这个错误消息是一个示例,在我们的数据库中,这个 TOAST 表 pg_toast_2619 存在数据损坏,这个表属于统计表(pg_statistic),它会被规划器用来做决策,以选择更好的计划来执行一个查询,这可能会直接影响数据库的性能,或者由于该错误而根本无法运行查询,此外,该表是通过 AUTOVACUM 进程或手动 ANALYZE 命令来填充和更新的,然后,如何解决此数据损坏,以继续在我们的数据库中正常工作?我们将在下一节中看到这一点。
解决方案
由于此表中存储的信息实际上是临时的,并且每次发生 ANALYZE 或由 AUTOVACUUM 触发 AUTO-ANALYZE 时,都会进行计算和存储,因此可以丢弃它们的数据,因为您可以再次生成,因此我们使用以下步骤来尝试解决这个问题。考虑到对表pg_statistic的访问仅限于超级用户,你需要以超级用户的身份来执行:
BEGIN;
DELETE FROM pg_statistic; -- delete data from pg_statistic
ANALYZE; -- populate the statistics table again
END;
根据数据库的大小,此活动可能需要一段时间,但是如果我们已确定数据损坏的行,以及它们属于哪个表,则可以仅删除与损坏的表对应的统计信息,并重新生成它们,从而可以减少新统计信息的重新创建时间。之所以可以检测到这一点,是因为它仅会在一个或几个表上返回上述错误。
BEGIN;
DELETE FROM pg_statistic where ((starelid::oid)::regclass)::text ='your_table'; -- delete data from pg_statistic for specific table
ANALYZE 'your_table'; -- populate the statistics table for specific table again
END;
结论
正如你所看到的,解决这个统计表数据损坏问题相对容易,现在规划器可以很好地工作,并对执行策略做出正确的决策,这也使得 AUTOVACUM 的工作会变得很好。所有损坏并影响 PostgreSQL 规划器或执行器的临时或可重构数据,都可以用这种方式进行修复,尝试重建对象,例如 pg_statistic_ext_data 表,或者对于损坏的索引可以进行 REINDEX,但除了这个解决方案,你也需要检查你的硬件并分析其健康状况,或验证你关于 fsync 的配置, 以避免数据损坏。
底层数据检查工具
PostgreSQL 还有其他的方法来发现和分析一些数据损坏,例如:amcheck、pageinspect 和 pg_visibility,在大多数情况下,您将需要技术支持来进行尝试和修复它。但请记住,PostgreSQL 中的数据损坏并不常见。