【问题标题】:Sequential Scan and Index Scan for primary key return different rows主键的顺序扫描和索引扫描返回不同的行
【发布时间】:2014-06-04 09:28:31
【问题描述】:

我的表 users 中的数据有问题。该表的主键定义为:

"primary_c26a3d1a9d1c7aa4bb0a8d6b752c01a7" PRIMARY KEY, btree (id)

当我使用WITH 子句强制对表进行顺序扫描时,我发现了重复的 ID:

=> WITH temp_table AS (select * from "users") SELECT id from temp_table group by id having count(id) > 1;
-[ RECORD 1 ]
id | 8225700
-[ RECORD 2 ]
id | 8225682
...

这是怎么发生的?如果我按索引搜索这些重复项,我不会遇到同样的问题:

=> select count(*) from users where id = 8225700;
-[ RECORD 1 ]
count | 1

我使用的是 PostgreSQL 9.1。

VACUUM 没有帮助我。我试图通过 ctid 删除重复项:

// good and bad rows
> with usrs as (select ctid, * from users) select ctid, id from usrs where id = 8225700;
ctid     |   id    
-------------+---------
(195669,33) | 8225700
(195708,34) | 8225700

// good row
select id, ctid from users where id = 8225700;
-[ RECORD 1 ]-----
id   | 8225700
ctid | (195708,34)

// deleting bad row
DELETE FROM users WHERE ctid = '(195669,33)';
ERROR:  update or delete on table "users" violates foreign key constraint   "foreign_1589fcbc580d08caf03e0fbaaca7d6dd" on table "account"

详细说明:Key (id)=(8225700) 仍然从account 表中引用。

但真正的行有引用,我不能删除它。

如何删除这些损坏的行?

【问题讨论】:

  • 你启用了autovacuum,是吗?
  • 没有数据库太大而无法自动清空。不过我今晚可以试试。
  • 如果数据库很大,您必须拥有 autovacuum,否则您会遇到事务 id 环绕问题。关闭 autovacuum 几乎总是一个坏主意(除非您确实有足够的手动清理策略)
  • 确切版本? SELECT version() 请。也请\x 然后SELECT * FROM pg_database WHERE datname = current_database();。 PostgreSQL 服务器日志中是否有任何信息?充其量这可能表明索引或堆损坏,但马是正确的,因为 xid 环绕也是一个非常现实的问题。请显示 WITH temp_table AS (select ctid, xmin, xmax, * from "users") SELECT ctid, xmin, xmax, id from temp_table group by id having count(id) > 1;select ctid, xmin, xmax from users where id = 8225700; 的输出。编辑问题,完成后在此处发表评论。
  • 请不要将查询及其结果发布为 cmets。 改为编辑您的问题!

标签: sql postgresql


【解决方案1】:
// deleting bad row DELETE FROM users WHERE ctid = '(195669,33)';
ERROR:  update or delete on table "users" violates foreign key
constraint   "foreign_1589fcbc580d08caf03e0fbaaca7d6dd" on table
"account"

In detail: Key (id)=(8225700) is still referenced from table
"account".

它说得很清楚:该行被account table 引用。

您需要找到参考并修复它。

UPDATE account SET fkey_field = ??? WHERE ... ;

详细信息取决于account 表的结构和内容。

如果您需要更多帮助,请从 psql 中粘贴 \d account\d users 的完整输出。

【讨论】:

    【解决方案2】:

    对我来说,这听起来像是一个糟糕的索引。尝试重建索引。

    reindex table users
    

    【讨论】:

      猜你喜欢
      • 2021-08-12
      • 2021-06-23
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-01-31
      • 2021-03-19
      • 2022-01-15
      相关资源
      最近更新 更多