我们正在PostgreSQL之上构建一个Java应用程序。它非常庞大且成功,至少应该可以运行几年。
不幸的是,我们(好吧,我)在设计过程的早期阶段犯了一个严重错误:所有数据库ID都是整数,从一个共享序列分发。
Java's max int is 2^31-1,大约有20亿。 PostgreSQL's integer type也是如此。该系统目前每天消耗大约1万个ID,随着新用户的增加,这个速度正在上升。
有一天,ID会用完并溢出。
我们正在寻找解决问题的方法。让我们立刻明白这一点:切换到Java的long
和Postgres'bigint
是一个干净的解决方案,但它是一个吨的工作。我们需要尽可能地推迟它。
到目前为止我们已经有了一些想法:
customer, timestamp
是完全有效的主键。
long
/ bigint
一个新序列。
在这些限制下,还有哪些其他方法会延迟ID耗尽?
答案 0 :(得分:3)
切换到long远不是一个干净的解决方案。如果你变得太大,那么只有一个合理的选择:UUIDs(yes, PostgreSQL comes with uuid data type)。
128位,大小为4个整数,但是你不想在几年内完成整个应用程序,再到这一切,你呢?当你变得太大而你需要对数据进行分片时,UUID会起作用。那时你不可能拥有共享序列,这就是为什么UUID有意义。
作为奖励,您甚至可以在每一行保留您的独特财产。
迁移并不困难:在PostgreSQL中添加一个带NULL的列很便宜,所以你可以先添加一个列,然后分批进行在线迁移,一次更新几千条记录,这样你就可以了没有停机时间。
然后,您可以使用两个外键测试相同的代码。 Java是否与laboratory或scientist类似?
这将是一项大量的工作吗?是的,但如果您的应用程序如此受欢迎,这显然是一个好兆头。
我也希望你在所有表格中使用相同的序列学到了一课。老实说 - 我真的没有看到附加价值。如果您想知道对象的位置,您也可以不同地命名主键(例如room_id,reservation_id等)。
答案 1 :(得分:1)
自从提出这个问题以来,我找到了解决问题一半的好方法 - 数据库方面。因此,对于后代,这是实现目标的方法。
查找integer
或integer[]
类型的所有数据库列。手动检查结果并删除类型列,例如text[]
。
SELECT *
FROM information_schema.columns cls
JOIN information_schema.tables tbl ON cls.table_name = tbl.table_name
WHERE
cls.table_schema = '<my schema>'
AND cls.data_type = 'integer' OR cls.data_type = 'ARRAY'
AND tbl.table_type = 'BASE TABLE';
为每个列准备数据类型更改DDL:
ALTER TABLE <one of the tables found>
ALTER COLUMN <one of its integral columns>
TYPE bigint;
除了VIEW
之外,它的效果非常好:他们不喜欢我改变他们的回归类型。我需要重新创建所有这些 - 序列将是
VACUUM
和ANALYZE
来修复慢速查询。bigint[]
无法转换为integer[]
。