整数超出范围且剩余磁盘空间太小无法将 id 转换为 bigint 和其他解决方案
Posted
技术标签:
【中文标题】整数超出范围且剩余磁盘空间太小无法将 id 转换为 bigint 和其他解决方案【英文标题】:integer out of range and remaining disk space too small to convert id to bigint and other solutions 【发布时间】:2018-03-22 03:09:15 【问题描述】:当我 insert
时,我得到 integer out of range
,因为我的 id/主键被错误地创建为 int
而不是 bigint
或 bigserial
。我试过了:
ALTER TABLE tbl ALTER COLUMN id TYPE BIGINT;
但我收到以下错误,因为我的可用磁盘空间不够大。
ERROR: could not extend file "base/16401/3275205": No space left on device
HINT: Check free disk space.
SQL state: 53100
我现在无法增加磁盘空间,出于令人沮丧的原因,我不会深入。
我还尝试重用 ids(我从这个表中删除了很多记录,所以有很大的差距)通过这样做来开始我的seq
:
https://dba.stackexchange.com/questions/111823/compacting-a-sequence-in-postgresql
但对于该链接中的解决方案 #1:
我假设我没有磁盘空间。该表为 117GB,我在...data/base
中有大约 24GB 可用空间。我确实有 150GB 可用空间用于存储我的临时文件(不同的挂载),这不是默认配置,但这样做是为了在 ...data/base
中为数据库存储节省空间。如果我可以在临时文件位置创建表,那可能会起作用,但我不知道该怎么做。
对于该链接中的解决方案 #2:
当我到达 update
部分时,我在 pgAdmin4 中得到了这个:
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 3.2 Final//EN">
<title>500 Internal Server Error</title>
<h1>Internal Server Error</h1>
<p>The server encountered an internal error and was unable to complete your request. Either the server is overloaded or there is an error in the application.</p>
但是当我运行时查询仍在运行:
select pid,query,state,wait_event,* from pg_stat_activity where state <> 'idle'
对于失败的update
查询,我没有收到任何服务器日志。
我最终杀死了那个更新查询,认为无论如何它最终都会失败。 (我再次运行这个,除非其他人有更好的主意,否则会让它运行上面的 html 错误。)
对于该链接中的解决方案 #3: 我有 16GM 的 RAM,所以还不够。
从这里开始: How to reset sequence in postgres and fill id column with new data?
我试过这个:
UPDATE table SET id = DEFAULT;
ALTER SEQUENCE seq RESTART;
UPDATE table SET id = DEFAULT;
ERROR: integer out of range
这会在您尝试插入时创建一个重复键:
ALTER SEQUENCE seq RESTART WITH 1;
UPDATE t SET idcolumn=nextval('seq');
还有什么我可以尝试的吗?
PostgreSQL 9.6
【问题讨论】:
您在其他驱动器上是否有任何空间可以创建一个表空间并将该表移到那里进行处理?否则你会被卡住。 在某处创建表空间,alter set tablespace new_tbs
,alter type bigint
并移回原始表空间 pg_default?..
@VaoTsun - 在概念上,是的。我以前从未对表空间做过任何事情。 new_tbs
是路径吗?现在查看文档。
是的,先在备用机器上练习。您不想在生产服务器上学习表空间。不过这很容易。您创建一个目录,将所有权设置为 postgres,将其初始化为表空间,在其上创建一个表空间,然后更改表集表空间以将其放在那里。非常方便的东西
将数据(或 pg_dump)转储到 .tsv、删除、重新创建、从 .tsv 加载或转储。
【参考方案1】:
Scott Marlowe 和 Vao Tsun cmets 工作:
在(linux)服务器上打开一个终端
导航到新命名空间的位置
创建一个目录:mkdir dirname
将所有权授予 postgres:chown postgres:postgres dirname
创建表:CREATE TABLESPACE new_tbl_space LOCATION '/path/dirname'
将表放入表空间:alter table tbl set tablespace '/path/dirname'
做占用这么多磁盘空间的事情:ALTER TABLE tbl ALTER COLUMN id TYPE BIGINT;
改回表空间:alter table tbl set tablespace pg_default
删除表空间:我是在 Tablespaces
节点/对象的 pgadmin4 中完成的
(那是凭记忆。如果我遗漏了什么,请告诉我。)
编辑:这具有重写整个表的副作用,就像一个完全真空释放任何死磁盘空间一样。
【讨论】:
@ScottMarlowe - 如果有兴趣,我的桌子尺寸会减小。试图找出原因和/或找到更好的策略:***.com/questions/46674520/… 执行此操作时必须锁定并重写整个表,因此很可能它会清除大量死元组,就像 Vacuum full 或 cluster 一样。 @ScottMarlowe - 好的。有没有办法在不做真空满的情况下减少这样的膨胀?此外,考虑到 pg 文档所说的如果你打算再次写信给桌子,这对我来说是一个惊喜。 有一些死空间是件好事。如果块中存在空白空间,PostgreSQL 可以更新许多行,这比写入新块并更新所有索引要快得多。这称为仅堆元组更新,是一个非常好的性能特性。 OTOH 有很多死空间会使其变慢,因为现在数据库在扫描块时必须毫无用处地穿过所有额外的空间。做到这一点的唯一方法是vacuum full / alter table(需要重写)和集群。所有这些都是阻塞操作。 你正在寻找的死空间是一个合理的平衡。大约 10% 到 20% 的空/死空间是一个不错的数字。因此,如果您有一个表,说 100MB 没有死空间,并且它膨胀到 120 到 150MB,那么就有足够的死空间用于更新,但并没有那么痛苦。但如果它测量到 500MB,那就太多了,而且真空度跟不上。您可以调整 vacuum_autovacuum_ 设置以使 autovacuum 更具侵略性。专门将vacuum_autovacuum_cost_delay 设置得更低,从20ms 到3 或4ms。有很大的不同。注意不要让你的 IO 泛滥以上是关于整数超出范围且剩余磁盘空间太小无法将 id 转换为 bigint 和其他解决方案的主要内容,如果未能解决你的问题,请参考以下文章