Jmo*_*y38 15 postgresql performance query-performance
相当简单的问题,可能在某处得到了回答,但我似乎无法为 Google 形成正确的搜索问题......
在查询该表的子集时,特定表中的列数是否会影响查询的性能?
例如,如果表 Foo 有 20 列,但我的查询只选择了其中的 5 列,那么有 20(而不是 10)列会影响查询性能吗?为简单起见,假设 WHERE 子句中的任何内容都包含在这 5 列中。
除了操作系统的磁盘缓存之外,我还担心 Postgres 的缓冲区缓存的使用。我对 Postgres 的物理存储设计一无所知。表存储在多个页面上(默认为每页 8k 大小),但我不太明白元组是如何从那里排列的。PG 是否足够聪明,只能从磁盘中获取包含这 5 列的数据?
Dan*_*ité 17
行的物理存储在Database Page Layout中的文档中进行了描述。同一行的列内容都存储在同一个磁盘页面中,除了TOAST 'ed 的内容(太大而无法放入页面)。内容在每行中按顺序提取,如下所述:
要读取数据,您需要依次检查每个属性。首先根据空位图检查该字段是否为空。如果是,请转到下一个。然后确保您有正确的对齐方式。如果该字段是固定宽度的字段,则所有字节都被简单地放置。
在最简单的情况下(没有 TOAST 的列),即使只需要很少的列,postgres 也会获取整行。所以在这种情况下,答案是肯定的,拥有更多的列可能会对垃圾缓冲区缓存产生明显的不利影响,特别是如果列内容很大而仍低于 TOAST 阈值时。
现在是 TOAST 情况:当单个字段超过 ~2kB 时,引擎会将字段内容存储到单独的物理表中。当整行不适合页面(默认为 8kB)时,它也会起作用:一些字段被移动到 TOAST 存储。Doc 说:
如果它是一个可变长度字段(attlen = -1),那么它会更复杂一些。所有变长数据类型共享公共头结构 struct varlena,其中包括存储值的总长度和一些标志位。根据标志,数据可以是内联的,也可以是在 TOAST 表中;它也可能被压缩
当没有明确需要时,不会提取 TOAST 的内容,因此它们对要提取的页面总数的影响很小(每列几个字节)。这解释了@dezso 答案中的结果。
至于写入,无论更改了哪些列,在每次 UPDATE 时都会完全重写每一行及其所有列。因此,对于写入而言,拥有更多列显然成本更高。
Erw*_*ter 10
Daniel 的回答侧重于读取单个行的成本。在这种情况下:将固定大小的NOT NULL
列放在表中会有所帮助。将相关列(您查询的列)放在首位会有所帮助。通过与列播放对齐俄罗斯方块来最小化填充(由于数据对齐)可能会有所帮助。但是最重要的效果还没有提到,尤其是对于大表。
额外的列显然会使一行覆盖更多的磁盘空间,因此一个数据页(默认为 8 kB)上容纳的行更少。单个行分布在更多页面上。数据库引擎通常必须获取整个页面,而不是单个行。单个行是更小还是更大一点无关紧要 - 只要必须读取相同数量的页面。
如果查询获取大表的(相对)一小部分,其中行或多或少随机地分布在整个表中,由索引支持,这将导致大致相同的页面读取次数,几乎不考虑到行大小。在这种(罕见的)情况下,不相关的列不会减慢你的速度。
通常,您将获取按顺序或邻近输入的行的补丁或集群并共享数据页。这些行由于混乱而分散,必须读取更多的磁盘页面才能满足您的查询。必须阅读更多页面通常是查询变慢的最重要原因。这就是为什么不相关的列使您的查询变慢的最重要因素。
对于大型数据库,通常没有足够的 RAM 将其全部保存在缓存中。更大的行占用更多的缓存、更多的争用、更少的缓存命中、更多的磁盘 I/O。磁盘读取通常要贵得多。SSD 的情况较少,但仍然存在显着差异。这增加了关于页面读取的上述观点。
它可能或不可能,如果不相关的列敬酒-ED关系。相关的列也可能被 TOAST 处理,带来很多相同的效果。
归档时间: |
|
查看次数: |
2169 次 |
最近记录: |