如何计算Postgresql中的最大列

Luk*_*101 7 sql postgresql

我想知道在postgresql表中计算最大列数的正确方法是什么.它在他们的网站上说:

每个表250 - 1600的最大列数取决于列类型

那么,根据列类型,我如何确定最大列?

vye*_*rov 9

您需要查看PostgreSQL的物理数据存储的详细信息Page Layout.

  1. 您可能知道,默认PostgreSQL块大小为8kB(8192字节).您还应该知道,在PostgreSQL表行中不能跨越块边界.这已经为您提供了8192字节的大小限制.但…

  2. 查看上面的页面布局,还有一些开销PageHeader,即当前PostgreSQL版本的24字节.所以,我们剩下8168个字节.但…

  3. 还有ItemIdData,这是指针数组.假设我们在此页面上只有1条记录,因此该条目仅占用4个字节(1个条目).所以,我们剩下8164个字节.但…

  4. 每条记录还有一个RecordHeader,已知占用23个字节.所以,我们剩下8141个字节.但…

  5. NULL紧接着之后还有一个-bitmap RecordHeader,但我们假设我们已经使用NOT NULL约束定义了所有列.所以,这里有8141个字节.但…

  6. 有这样的事情 - MAXALIGN.看看Erwin的精彩回答.我们在24+4+23=51这里谈到抵消.现在一切都取决于系统上此参数的值.

    如果它是32位,那么offset将与52对齐,这意味着我们又浪费了一个字节.

    如果它是64位,那么offset将对齐到54,这意味着我们浪费了3个字节.我的系统是64位的,所以我假设我们剩下8138个字节.

所以这就是我们留下的空间.现在一切都将取决于我们选择的列的类型以及它们如何坐在一起(记住那MAXALIGN件事).我们来看看int2所有专栏.简单的计算表明我们应该能够挤入这种类型的4069列:所有列NOT NULL和相同类型.

简单的脚本:

echo "CREATE TABLE tab4069 (" > tab4069.sql
for num in $(seq -f "%04g" 1 4069); do
  echo "    col$num  int2 not null," >> tab4069.sql; done
echo "    PRIMARY KEY (col0001) );" >> tab4069.sql
Run Code Online (Sandbox Code Playgroud)

不过,如果您尝试创建此表,则会遇到错误:

错误:表最多可包含1600列

一些搜索指向类似的问题,并查看PostgreSQL的来源,我们得到答案(第23到47行):

/*
 * MaxTupleAttributeNumber limits the number of (user) columns in a tuple.
 * The key limit on this value is that the size of the fixed overhead for
 * a tuple, plus the size of the null-values bitmap (at 1 bit per column),
 * plus MAXALIGN alignment, must fit into t_hoff which is uint8.  On most
 * machines the upper limit without making t_hoff wider would be a little
 * over 1700.  We use round numbers here and for MaxHeapAttributeNumber
 * so that alterations in HeapTupleHeaderData layout won't change the
 * supported max number of columns.
 */
#define MaxTupleAttributeNumber 1664        /* 8 * 208 */

/*
 * MaxHeapAttributeNumber limits the number of (user) columns in a table.
 * This should be somewhat less than MaxTupleAttributeNumber.  It must be
 * at least one less, else we will fail to do UPDATEs on a maximal-width
 * table (because UPDATE has to form working tuples that include CTID).
 * In practice we want some additional daylight so that we can gracefully
 * support operations that add hidden "resjunk" columns, for example
 * SELECT * FROM wide_table ORDER BY foo, bar, baz.
 * In any case, depending on column data types you will likely be running
 * into the disk-block-based limit on overall tuple size if you have more
 * than a thousand or so columns.  TOAST won't help.
 */
#define MaxHeapAttributeNumber  1600       /* 8 * 200 */
Run Code Online (Sandbox Code Playgroud)

有许多可变长度类型,它们执行1或4个字节的固定开销+实际值中的一些字节数.这意味着你永远不会事先知道记录在获得实际价值之前需要多少空间.当然,这些值可以通过TOAST单独存储,但通常是较大的值(总长度为2kB).

请查阅有关类型的官方文档,以找出用于固定长度类型的空间.您还可以检查pg_column_size()任何类型的函数输出,尤其是复杂的函数,如数组hstorejsonb.

如果您想要对此主题有更完整的愿景,您将不得不深入了解更多细节.