5

我的问题与 Postgres 的工作原理有关:

我有一张桌子:


CREATE TABLE A (
   id SERIAL,  
   name VARCHAR(32),
   type VARCHAR(32) NOT NULL, 
   priority SMALLINT NOT NULL,
   x SMALLINT NOT NULL,
   y SMALLINT NOT NULL,
   start timestamp with time zone,
   end timestamp with time zone,
   state Astate NOT NULL,
   other_table_id1 bigint REFERENCES W,
   other_table_id2 bigint NOT NULL REFERENCES S,
   PRIMARY KEY(id)
); 

在 other_table_id1、state 和 other_table_id2 上有附加索引。

该表非常大,并且在列上看到了很多更新:other_table_id1,state。开始和结束列的一些更新,但其余的都是不可变的。(Astate 是列状态的枚举类型。)

我想知道将两个最常更新的列拆分到单独的表中是否有意义。我希望获得的是性能,因为当我只是查找该信息时,或者减少更新的重量,因为(也许?)读取和写入较短的行成本更低。但是,当(偶尔)需要一次获取特定项目的所有数据时,我需要权衡连接成本。

有一次,我的印象是每一列都是单独存储的。但后来,当我在某处读到减小表一侧列的宽度确实会对使用另一列查找数据时的性能产生积极影响时,我修改了我的想法(因为行存储在一起,所以总行长度会更短)。所以我现在的印象是一行的所有数据都物理存储在磁盘上。所以建议的表格拆分听起来会很有帮助。当我当前写入 4 个字节来更新状态时,我是否相信我正在重写实际上永远不会改变的 64 个字节的文本(名称、类型)?

我对表“规范化”不是很有经验,也不熟悉 Postgres 的内部结构,所以我正在寻找建议和特别是最佳实践来估计权衡,而不必先做这项工作,然后确定这项工作是否值得. 这种变化需要在重写已经高度优化的查询方面付出相当大的努力,所以我宁愿深入了解我可以期待什么结果。谢谢,M。

4

3 回答 3

4

更新更大的行有一定的成本。

一个公式可以帮助解决这个问题。如果你不拆分,你的成本是

成本 = xU + yS

在哪里:

U = 整行的更新(表未拆分)

S = 选择成本

x,y = 动作计数

然后,如果你拆分它,你试图弄清楚:

成本 = gU1 + hU2 + xS1 + yS2

在哪里

U1 = 更小表的更新(成本更低)

U2 = 更新更大的表(成本更低)

S1 = 从较小的表中选择

S2 = 从更大的表中选择

g,h,x,y = 单个动作发生的频率

因此,如果 g >> h,将它们分开是值得的。特别是如果 x >> y 那么它真的很划算。

编辑:在回应评论时,我还要指出,如果数据库处于持续负载状态,没有不活动,这些成本变得更加重要。相反,如果服务器没有经历持续的负载,它主要是不活动的,每秒只有 1 或 2 个 trx,长时间不活动(其中“长”= 几秒钟),那么,如果是我,我不会复杂化我的代码,因为性能优势不会显示为真正可衡量的东西。

于 2011-02-02T19:12:10.090 回答
2

与此有关的 Postgresql 实现细节之一是它从不“更新”存储在磁盘上的行,它总是写入新版本。因此,在开始时将固定宽度的列放在一起并没有快速的胜利,就像使用 Oracle 一样,例如 (iirc)。

确实,根据是否倾向于一起更新,将不同表中的列分组在一起可以产生更少的需要清理的垃圾。实验和测量结果是这里的关键。例如,如果您有一些经常更新的数据,您应该调查表上的“填充因子”设置。此设置使 PostgreSQL 在插入时在表页中保留一些空闲空间,允许将更新版本的行尽可能添加到与先前版本相同的页中:这可以减轻更新的负担,因为它可能意味着索引指向行不必更新,代价是让表占用更多磁盘空间。

正如 Xaade 所提到的,有很多关于这个主题的材料。我想强调一下我的评论,即需要衡量所做的任何更改的影响。有时看起来像是大获全胜的东西在实践中并不奏效。

于 2011-02-02T23:04:12.683 回答
0

无论列如何存储,都值得将其拆分。您在并发方面遇到的问题要少得多,加快对部分数据的查找速度,通过提供三个索引来搜索而不需要创建这些辅助键来加速索引搜索等等。

您可以通过作弊或一次只允许查看这么多行来减少内部连接的影响。您可以通过提供界面而不是允许直接查找、仅在可见行上显示内部连接数据(一次只能在屏幕上查看这么多行)或通过显示当前选定行的附加数据或通过每次使用浏览按钮查找时只允许 X 行。如果您使用作弊,请确保缓存扩展查找的结果。

于 2011-02-02T19:03:14.397 回答