我有 2 个表,其中包含以下模式,行数相等。当我运行SELECT relname, relpages FROM pg_class ORDER BY relpages DESC
命令时,它们显示为 23GB,即使这两个模式的数据类型(总字节数)导致大小不同。找出通过组合表格可以节省多少空间的最佳方法是什么?另外,有什么方法可以确定每行实际占用多少空间?
Table "public.table1"
Column | Type | Modifiers
--------------+--------------------------+-----------------------------------------------------
field1 | smallint |
field2 | smallint |
field3 | integer |
field4 | smallint |
timestamp | timestamp with time zone |
user_id | integer |
status | boolean |
id | integer | not null default
Table "public.table2"
Column | Type | Modifiers
----------------+--------------------------+----------------------------------------------------
user_id | integer |
begin_timestamp | timestamp with time zone |
end_timestamp | timestamp with time zone |
field | smallint | not null
id | integer | not null default
因为生成的组合表中每个表的记录都有未使用的行,所以很可能您不会获得空间,反而会失去空间。
比这更重要的是,出于磁盘空间的原因,我强烈反对做出这种性质的架构决策。磁盘很便宜——设计精良且功能齐全的应用程序则不然。如果存在运行时性能问题(即所有 46 GB 都被加载到内存/交换空间),那么您可能会遇到优化和调整问题。
一个合理的答案必须恕我直言问(或至少暗示)这个问题:为什么要拆分表?(更重要的是:它仍然适用吗?)
一般情况: 我不知道 postgres 数据库引擎如何工作的细节,但节省的磁盘空间的下限可能不大于删除的列的大小 + 重复变量的索引 + 一些内务数据
上限也很小,所以可能不值得这么麻烦;甚至可能是出于性能原因对它们进行了分区——因为某些列将被更频繁地访问(读取,甚至更新),因此可以将其变小(更少的列)以使其更快。(同时从两者访问列会受到一些惩罚。)
具体情况: 看起来他们之间有很多冗余字段。例如,user_id 不需要出现两次。begin/end/X 时间戳也许可以减少到两个或一个。因此,根据应用程序的要求,可能会略有节省。再次尝试弄清楚他们为什么这样做。
不过,总的来说,我同意 Bryan Agee 的观点;磁盘空间可能不应该是你关心的任何大到足以开始运行 postgres 的东西。特别是如果您因花在“修复”这个问题上的时间而获得报酬,那么该成本可能会超过更大磁盘本身的成本。
每行空间: 我不太精通postgres的细节,所以知道的人应该能够纠正任何错误。例如有办法询问 postgres 该特定行实际占用了多少空间;我一个都不知道。我正在写的基本上是数据库存储背后的理论,就像(我相信)今天普遍做的那样。
每个字段都有一个位(在它自己的一个字节中,或者在整行共有的位集中)表示该值是否为空。如果它是空值,则不会再存储任何内容。然后是一个长度字节——除非这是固定宽度数据类型中隐含的。然后是数据本身。
因此,一行一个 int(即使是 64 位)和三个空值可能只需要 3 个字节。(对于 <127 的值,存储 size=1 和字节。)加上索引和各种其他管家元数据。同样,我不知道 postgres 在这方面走了多远。而这些因素加在一起,往往会使“这一行占多少”成为一个无用答案的问题。
AFAIK postgres 还使用“页面”进行操作 - 一行不能跨边界存储的空间块。因此,较大的记录可能更经常地“只是不适合”在一个页面中,因此需要放置在另一个/新页面中。