【问题标题】:Increase the precision of a numeric datatype without locking the table在不锁定表的情况下提高数值数据类型的精度
【发布时间】:2017-10-11 02:20:20
【问题描述】:

我想提高包含 10+ 百万条记录的大型表中数字列的精度。 ALTER TABLE mytable ALTER COLUMN mycolumn TYPE numeric(15,6) 的标准方式将锁定表。这是一个高度事务性的表。有没有办法在不锁定表、不重新创建表、复制数据和重命名/交换表的情况下做到这一点?我目前正在运行 dockerized postgres 9.5

【问题讨论】:

  • 原始列定义是什么?当您不更改 precision 时,该表将 not 被重写,例如从(12,6)(15,6) 不会发生重写。

标签: postgresql alter-table


【解决方案1】:

我不认为更改 typmod 需要重写全表,但快速检查表明,如果您在 finish_heap_swap 中设置断点,它实际上会重写像 ALTER TABLE test_numeric ALTER COLUMN x TYPE numeric(8,4) 这样的 cmd - 至少在 9.5 中。


编辑a_horse_with_no_name 指出只有在更改精度而不是比例时才会执行重写。因此,您可能可以使用不会严重中断操作的短期排他锁来做到这一点。


否则:

您可能会作弊并直接更新系统目录,因为您知道新精度将适用于所有具有旧精度的行。但我有点犹豫,因为如果它这么简单,那么 PostgreSQL 很可能已经做到了。我不推荐它,但如果你想尝试、测试、阅读等,你可以从那里开始。

对于带有列x numeric(4,2) 的表test_numeric

test=> select atttypmod from pg_attribute where attrelid = 'test_numeric'::regclass AND attname = 'x';
 atttypmod 
-----------
    262150
(1 row)

如果我将ALTER 转为15,6

test=> select atttypmod from pg_attribute where attrelid = 'test_numeric'::regclass AND attname = 'x';
 atttypmod 
-----------
    983050
(1 row)

(我懒得阅读 typmod 的代码来了解 32 位 typmod 字段是如何分解为精度和比例的,但如果你愿意,你可以这样做。)

应该使用新的 atttypmod 对UPDATE pg_attribute 条目是安全的。但正如我所说,先做一些阅读和研究,看看你是否能找到先前关于直接 typmod 更新的讨论。

适用于延长VARCHAR(n) 的任何内容也将适用于NUMERIC,因为两者在内部都是VARLENA 存储类型,并且都具有typmods,其中较大的值是较小值的纯超集。您可能会发现更多关于人们询问是否在不重写的情况下延长 VARCHAR 的信息。

【讨论】:

  • 似乎只有在更改精度时才会进行重写。例如当从(8,2)(10,2) 时,表被重写。但是从(8,2)(10,4) 它被重写了。
  • @a_horse_with_no_name 好收获!
  • @a_horse_with_no_name 谢谢!我已经在我的测试中证实了这一点。虽然我认为文档可能需要更清楚一点。我不是这样读的。哦,好吧。
  • 不确定这是否重要,但对于像我这样困惑的人来说,我认为 a_horse_with_no_name 表述有误。他们提出的示例(以及我在 strong_migrations gem 中看到的证实)是,仅当您更改 SCALE NOT PRECISION 时才会发生重写。您可以在文档中看到数据类型是如何定义的-postgresql.org/docs/14/datatype-numeric.html#id-1.5.7.9.7.4 与他们的示例相比(第二个值是 Scale,第一个是 Precision)
猜你喜欢
  • 1970-01-01
  • 2019-01-01
  • 1970-01-01
  • 2019-08-18
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-10-15
  • 2020-01-29
相关资源
最近更新 更多