以下日志消息在postgres日志文件中可用数千次。如何解决。
pg_toast_2619中的toast值815441缺少块号0。
pg_toast_2619是pg_statistic表。它(pg_statistic)也包含重复的记录。如何解决这种情况。这背后的原因是什么。
答案 0 :(得分:3)
服务器出了问题。服务器崩溃了?磁盘故障? 无论如何你可以这样做:
def run
: ReadOnlyKeyValueStore[String, String] => String => Int => Unit =
(store: ReadOnlyKeyValueStore[String, String]) => (hostname: String) => (port: Int) =>
???
并在之后发出DELETE FROM pg_catalog.pg_statistic;
。如果错误仍然存在:
ANALYZE
(Postgres 9.4 +)ALTER
SYSTEM SET allow_system_table_mods = ON;
TRUNCATE TABLE pg_catalog.pg_statistic;
ANALYZE VERBOSE;
执行此操作后,您可能需要ALTER SYSTEM RESET
allow_system_table_mods;
。
有关allow_system_table_mods here的更多信息。
答案 1 :(得分:0)
假设损坏的表名为 mytable
。
互联网上的许多文章都建议对数据库进行以下查询:
psql> select reltoastrelid::regclass from pg_class where relname = 'mytable';
reltoastrelid
-------------------------
pg_toast.pg_toast_40948
(1 row)
然后触发以下命令:
REINDEX table mytable;
REINDEX table pg_toast.pg_toast_40948;
VACUUM analyze mytable;
但就我而言,这还不够。
然后,我计算了 mytable
中的行数:
psql> select count(*) from mytable;
count
-------
58223
要查找损坏,可以从表中获取数据,直到出现'Missing chunk...' 错误。因此,以下一组查询可以完成这项工作:
select * from mytable order by id limit 5000 offset 0;
select * from mytable order by id limit 5000 offset 5000;
select * from mytable order by id limit 5000 offset 10000;
select * from mytable order by id limit 5000 offset 15000;
select * from mytable order by id limit 5000 offset 20000;
...
...依此类推,直到出现错误。在此示例中,如果您达到 55000 的偏移量(55000 + 5000 是 60000,超过记录总数)而没有出现错误,那么您的表没有损坏。 order by
子句对于使您的查询可重复是必要的,即确保查询不会随机返回行,并且 limit
和 offset
子句按预期工作。如果您的表没有 id
字段,您必须找到一个合适的字段进行排序。出于性能原因,最好选择索引字段。
为了更快并且不弄脏您的控制台,可以直接从控制台触发查询,将输出重定向到 /dev/null
并仅在发现错误时打印错误消息:
psql -U pgsql -d mydatabase -c "select * from mytable order by id limit 5000 offset 0" > /dev/null || echo "Corrupted chunk read!"
上述语法表示:执行查询并将输出重定向到/dev/null
,或者,如果出现错误(||),则写入错误消息。
假设第一个给出错误的查询如下:
select * from mytable order by id limit 5000 offset 10000;
Corrupted chunk read!
>
现在,您知道损坏的块位于 10000 到 14999 之间的行中。因此,您可以通过将查询 LIMIT 子句减半来缩小搜索范围。
select * from mytable order by id limit 2500 offset 10000;
Corrupted chunk read!
>
因此,错误发生在 10000 到 12499 之间的行中。我们再次将行数限制减半。
select * from mytable order by id limit 1250 offset 10000;
>
获取 10000 到 12499 之间的行不会返回任何错误。所以错误必须在 11250 和 12499 之间的行中。我们可以通过触发查询来确认这一点:
select * from mytable order by id limit 1250 offset 11250;
Corrupted chunk read!
>
所以,我们再次将限制减半。
select * from mytable order by id limit 625 offset 11250;
>
select * from mytable order by id limit 625 offset 11875;
Corrupted chunk read!
>
...
您应该继续缩小,直到准确找到损坏的行:
...
select * from mytable order by id limit 1 offset 11963;
Corrupted chunk read!
>
请注意,在最后一个查询中,LIMIT 1
子句仅标识一行。
最后,你必须找到损坏行的 id 并删除它(显然你有数据丢失):
psql> select id from mytable order by id limit 1 offset 11963;
id
--------
121212
psql> delete from mytable where id = 121212;
DELETE 1
>
在搜索损坏的行期间,请考虑损坏最有可能发生在最后插入/更新的记录中,即使这不是一般规则。所以你可以选择一个尊重物理插入/更新的排序键,以减少扫描时间。
如果您更喜欢完全自动化损坏的行搜索,请考虑使用以下脚本(在 csh 语法中):
#!/bin/csh
set j = 0
while ($j < 58223) //here the total number of table rows
psql -U pgsql -d mydatabase -c "SELECT * FROM mytable LIMIT 1 offset $j" >/dev/null || echo $j
@ j++
end
此脚本打印所有损坏行的数量。在长表的情况下,它可能需要很长时间,因为它会执行与表行数一样多的查询。
我在一个要点中发布了同样的问题,here。