Postgres 表中列的顺序会影响性能吗?

Posted

技术标签:

【中文标题】Postgres 表中列的顺序会影响性能吗?【英文标题】:Does the order of columns in a Postgres table impact performance? 【发布时间】:2012-09-18 06:10:02 【问题描述】:

在 Postgres 中,CREATE TABLE 语句中的列顺序会影响性能吗?考虑以下两种情况:

CREATE TABLE foo (
  a      TEXT, 
  B      VARCHAR(512),
  pkey   INTEGER PRIMARY KEY,
  bar_fk INTEGER REFERENCES bar(pkey),
  C      bytea
); 

对比

CREATE TABLE foo2 (
  pkey   INTEGER PRIMARY KEY,
  bar_fk INTEGER REFERENCES bar(pkey),
  B      VARCHAR(512),      
  a      TEXT, 
  C      bytea
);

foo2 的性能是否会因为列的字节对齐更好而优于foo?当 Postgres 执行 CREATE TABLE 时,它是按照指定的列顺序还是按照字节对齐或性能的最佳顺序重新组织列?

【问题讨论】:

【参考方案1】:

问题 1

foo2的性能会不会比foo更好,因为字节更好 列对齐?

是的,列的顺序对性能的影响很小。类型对齐是更重要的因素,因为它会影响磁盘占用空间。您可以最小化存储大小(播放“俄罗斯方块”)并在数据页上压缩更多行 - 这是提高速度的最重要因素。

通常不值得打扰。通过这个相关答案中的极端示例,您会得到很大的不同:

Calculating and saving space in PostgreSQL

类型对齐细节:

Making sense of Postgres row sizes

另一个因素是,如果您首先有固定大小的列,则检索列值会稍微快一些。我引用manual here:

要读取数据,您需要依次检查每个属性。第一的 根据空位图检查该字段是否为空。如果它 就是,去下一个。然后确保你有正确的对齐方式。如果 该字段是一个固定宽度的字段,那么所有的字节都是简单的 放置。如果它是一个可变长度字段(attlen = -1),那么它有点 更复杂。所有变长数据类型共享一个共同的 头结构struct varlena,包含总长度 存储的值和一些标志位。

有一个开放的TODO item to allow reordering of column positions in the Postgres Wiki,部分原因是这些原因。

问题 2

当 Postgres 执行 CREATE TABLE 时,它是否遵循列顺序 指定或是否以字节的最佳顺序重新组织列 对齐还是性能?

列按定义的顺序存储,系统不会尝试优化。

我没有看到列顺序与 TOAST tables 的任何相关性,就像另一个答案似乎暗示的那样。

【讨论】:

PostgreSQL 项目想要添加自动物理顺序优化。 wiki.postgresql.org/wiki/… 点赞! text 和 varchar 如何在这种对齐方式中工作 @PirateApp: textvarchar 使用“字符对齐”,即不对齐。我添加了详细信息的链接。【参考方案2】:

据我了解,PostgreSQL 在保存记录时遵循您输入列的顺序。这是否会影响性能是值得商榷的。 PostgreSQL 将所有表数据存储在每个大小为 8kb 的页面中。 8kb 是默认值,但可以在编译时更改。

表格中的每一行都会占用页面内的空间。由于您的表定义包含可变列,因此页面可以包含可变数量的记录。您要做的是确保您可以将尽可能多的记录放入一页中。这就是为什么当表具有大量列或列大小很大时,您会注意到性能下降的原因。

话虽如此,声明 varchar(8192) 并不意味着页面将被一条记录填满,但声明 CHAR(8192) 将用完一整页,而与列中的数据量无关。

在声明 TEXT 列等 TOASTable 类型时,还需要考虑一件事。这些是可能超过最大页面大小的列。具有 TOASTable 列的表将具有关联的 TOAST 表来存储数据,并且只有指向数据的指针与表一起存储。这可能会影响性能,但可以通过在 TOASTable 列上使用适当的索引来改善。

总而言之,我不得不说,列的顺序对表的性能没有太大的影响。大多数查询使用单独存储的索引来检索记录,因此列顺序被否定。这取决于需要读取多少页才能检索数据。

【讨论】:

您似乎暗示了列顺序和 TOAST 表之间的联系,我看不到。关于TOAST 的部分只是题外话。此外,您关于索引的段落不正确。在大多数情况下,除了扫描索引之外,Postgres 还必须从表中读取实际行(Postgres 9.2 的新 index-only scan 功能是个例外——它只在最佳条件下工作)。索引有很大帮助,但不能完全否定列顺序的影响。 我并不是说列顺序和 TOAST 表之间存在联系。 TOASTable 列只是在查看表性能时要查看的另一件事。扫描索引后,这完全取决于需要读取多少页才能加载数据。因此列顺序没有影响。

以上是关于Postgres 表中列的顺序会影响性能吗?的主要内容,如果未能解决你的问题,请参考以下文章

将 postgres 中列的值更新为小写

COUNT() 对表中列的影响

列存储索引中列的顺序在 SQL Server 2012 中是不是重要

WHERE 子句中的字段顺序会影响 MySQL 的性能吗?

Toad 问题:Oracle 类型作为显示所有记录的表中列的数据类型

如何将一个表中列的每个不同值映射到 Hive 中另一个表中列的每个不同值