将列从timestamp更改为timestamptz会锁定表吗?

问题描述 投票:0回答:1

我想将列从

timestamp
(无时区)迁移到
timestamptz
类型。

我使用的是 Postgres 9.3.9。

我需要知道此操作是否会导致表重写(锁定表),因为我的表很大并且数据库处于活动状态。

我在 9.2 发行说明中找到了这个

增加 varchar 或 varbit 列的长度限制,或完全删除该限制,不再需要重写表。同样,增加数字列允许的精度,或将列从受约束的数字更改为不受约束的数字,不再需要重写表。在涉及间隔、时间戳和时间戳类型的类似情况下,也可以避免表重写。

这听起来很有希望,但实际上并没有详细说明“类似案例”可能是什么。

如果此操作将锁定表,我希望获得有关如何在实时数据库上解决此问题而不中断服务的建议。

postgresql concurrency timestamp postgresql-9.3 alter-table
1个回答
6
投票

首先,您似乎混淆了锁和表重写。发行说明中的注释谈到了表重写 - 它总是在表上使用

ACCESS EXCLUSIVE
。但这里还有许多其他操作也需要锁。

您需要:

ALTER TABLE tbl ALTER ts_col TYPE timestamptz;

除非您想在转换中设置特定时区,而不是会话的当前时区:

ALTER TABLE tbl ALTER ts_col TYPE timestamptz USING ts_col AT TIME ZONE 'Europe/London';

在这种情况下,请务必使用时区名称不是简单的偏移量或缩写。详情:

说明书:

ALTER TABLE
更改现有表的定义。有 下面描述了几个子表单。请注意所需的锁定级别 每个子表单可能有所不同。
ACCESS EXCLUSIVE
锁被持有,除非 明确指出。

ALTER column_name TYPE data_type
需要这样一个
ACCESS EXCLUSIVE
。虽然 timestamp
timestamptz
的内部存储
format
相同,但内部 value 通常会因转换而更改(取决于会话的时区设置!)。 Postgres 必须为表中的每一行编写新版本,因此这也需要表重写。由于该操作需要
ACCESS EXCLUSIVE
,因此无需保留旧的行版本,并且转换后您将看不到死元组。

fiddle - 演示时区设置对转换的作用。我还添加了一个将

varchar
转换为
text
的示例,这不需要重写表 - 除非您使用更短的长度修饰符。

sqlfiddle - 请注意输出强制转换为 text (

ts_col::text
),以防止 sqlfiddle 中的 JDBC 层添加更多(不需要的!)表示魔法。

事务开始后尝试访问表的并发事务将

等待,直到该事务完成。

可以

尝试通过在后台准备一个新表、删除旧表并重命名新表来缩短锁定时间,但这将使并发事务失败并出现如下错误:

错误:无法打开与 OID 123456 的关系

详情:

    在大表中填充新列的最佳方法?
  • “类似案例”
timestamp

/
timestamptz

varchar

numeric
timestamp
time
interval
类型
 允许使用 
修饰符
。例如,时间戳默认最多存储 6 位小数秒,但您可以修改:timestamp(0) 不存储秒小数。

varchar(10)

->

varchar(20)
的转换不需要重写表,因为源类型中的值也保证适合(二进制兼容)目标类型。
对于 

timestamp (0)

->

timestamp
timestamptz(3)
->
timestamptz(5)
也是如此。这就是手册在发行说明中引用的
段落中提到的内容

在涉及以下内容的类似情况下,也可以避免表重写
interval

timestamp
timestamptz
类型。

    

© www.soinside.com 2019 - 2024. All rights reserved.