我们有一个巨大的表,其中包含主键索引上的膨胀。我们不断在该表上存档旧记录。
我们通过同时创建索引并删除旧索引来重新索引其他列。这是为了避免干扰生产流量。 但这对于主键是不可能的,因为有依赖于它的外键。至少基于我们的尝试。
在不阻止表上DML语句的情况下安全地重新索引主键的正确方法是什么?
答案 0 :(得分:1)
您可以为此使用pg_repack。
pg_repack是PostgreSQL的一个扩展,可让您从表和索引中删除膨胀,并有选择地恢复聚簇索引的物理顺序。
在整个过程中,它不持有排他锁。它仍然会执行一些锁定,但这应该只在短时间内。您可以在此处查看详细信息:https://reorg.github.io/pg_repack/
要对索引执行重新打包,您可以尝试:
pg_repack -t table_name --only-indexes
答案 1 :(得分:0)
仅使用其索引名称reindex作为其他索引:
REINDEX INDEX <indexname>;
让我们创建一个具有主键约束的表,该约束也是一个索引:
CREATE TABLE test(
Id BIGSERIAL PRIMARY KEY
);
在目录中,我们看到约束名称:
SELECT conname FROM pg_constraint WHERE conname LIKE 'test%';
-- "test_pkey"
有了索引的名称,我们可以对其重新索引:
REINDEX INDEX test_pkey;
您还可以在创建时修复约束名称:
CREATE TABLE test(
Id BIGSERIAL NOT NULL
);
ALTER TABLE test ADD CONSTRAINT myconstraint PRIMARY KEY(Id);
如果必须解决并发问题,请使用建议的方法a_horse_with_no_name
create a unique index concurrently:
-- Ensure Uniqueness while recreating the Primary Key:
CREATE UNIQUE INDEX CONCURRENTLY tempindex ON test USING btree(Id);
-- Drop PK:
ALTER TABLE test DROP CONSTRAINT myconstraint;
-- Recreate PK:
ALTER TABLE test ADD CONSTRAINT myconstraint PRIMARY KEY(Id);
-- Drop redundant Index:
DROP INDEX tempindex;
要检查索引是否存在:
SELECT * FROM pg_index WHERE indexrelid::regclass = 'tempindex'::regclass
答案 2 :(得分:0)
REINDEX CONCURRENTLY
似乎也有效。我在我的数据库上试了一下,没有出现任何错误。
REINDEX INDEX CONCURRENTLY <indexname>;
我认为它可能与@jlandercy 在他的回答中描述的类似。在重新索引运行时,我看到一个带有后缀 _ccnew
的索引,并且现有的索引也完好无损。最终,我猜想在删除旧索引后,该索引被重命名为原始索引,并且我最终在我的表上看到了一个唯一的主索引。
我正在使用 postgres v12.7
。