6

在我的项目中,有 2300 万条记录和大约 6 个字段已被该表索引。

早些时候,我测试了为 Thinking Sphinx 搜索添加 delta 列,但它会将整个数据库锁定一个小时。之后,当添加文件并尝试重建索引时,这是保持数据库锁定约 4 小时的查询:

"update user_messages set delta = false where delta = true"

好吧,为了建立服务器,我从 db dump 中创建了一个新数据库并将其提升为数据库,以便可以启动服务器。

现在我正在寻找的是在没有表锁的情况下在我的表中添加增量列是可能的吗?一旦delta添加了列,为什么在我运行索引重建命令时执行上述查询,为什么它会阻塞服务器这么长时间?

PS.:我在 Heroku 上并使用带有 ika db 模型的 Postgres。

4

2 回答 2

8

Postgres 11 或更高版本

从 Postgres 11 开始,只有 volatile 默认值仍然需要重写表。手册:

添加具有volatile DEFAULT的列或更改现有列的类型将需要重写整个表及其索引。

大胆强调我的。false是不可变的。所以只需添加带有DEFAULT false. 超级快,完成工作:

ALTER TABLE tbl ADD column delta boolean DEFAULT false;

Postgres 10 或更高版本,或用于 volatileDEFAULT

添加新列而不 DEFAULT强制或DEFAULT NULL通常不会强制表重写,并且非常便宜。仅向其写入实际值会创建新行。但是,引用手册:

添加带有DEFAULT子句的列或更改现有列的类型将需要重写整个表及其索引。

UPDATE在 PostgreSQL 中写入行的新版本。您的问题并未提供所有信息,但这可能意味着要编写数百万行新行。

在执行UPDATE就地操作时,如果表的主要部分受到影响并且您可以自由地以独占方式锁定表,请在执行批量操作之前删除所有索引并在UPDATE之后重新创建它们。这种方式更快。手册中的相关建议。

如果您的数据模型和可用磁盘空间允许,则CREATE在后台创建一个新表,然后在一个事务中:DROP旧表和RENAME新表。有关的:

在后台创建新表时:一次将所有更改应用于同一行。重复更新会创建新的行版本并留下死元组。

如果由于限制而无法删除原始表,另一种快速方法是构建一个临时表,TRUNCATE即原始表并大量INSERT新行 - 排序,如果这有助于提高性能。一站式交易。像这样的东西:

BEGIN

SET temp_buffers = 1000MB;  -- or whatever you can spare temporarily

-- write-lock table here to prevent concurrent writes - if needed
LOCK TABLE tbl IN SHARE MODE;    

CREATE TEMP TABLE tmp AS
SELECT *, false AS delta
FROM   tbl;                -- copy existing rows plus new value
-- ORDER BY ???            -- opportune moment to cluster rows

-- DROP all indexes here

TRUNCATE tbl;              -- empty table - truncate is super fast

ALTER TABLE tbl ADD column delta boolean DEFAULT FALSE; -- NOT NULL?

INSERT INTO tbl
TABLE tmp;                 -- insert back surviving rows.

-- recreate all indexes here

COMMIT;
于 2012-05-02T11:26:19.447 回答
0

您可以添加另一个具有一列的表,不会有这么长的锁。当然应该有另一列,第一列的外键。

对于索引,您可以使用“CREATE INDEX CONCURRENTLY”,它不会在此表http://www.postgresql.org/docs/9.1/static/sql-createindex.html上使用太重的锁。

于 2012-05-02T11:47:28.503 回答