如何计算Postgresql中的最大列

时间:2014-10-05 17:54:59

标签: sql postgresql

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

  

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

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

1 个答案:

答案 0 :(得分:8)

您需要查看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之后还有一个RecordHeader - 位图,但我们假设我们已经使用NOT NULL约束定义了所有列。所以,这里有8141个字节。但是......

  6. 有这样的事情 - MAXALIGN。看看at this wonderful answer by Erwin。 我们在这里说24+4+23=51偏移。 现在一切都取决于系统上此参数的值。

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

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

  7. 所以这就是我们留下的空间。现在一切都取决于我们选择的列的类型以及它们如何组合在一起(请记住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
    

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

      

    错误:表格最多可包含1600列

    the similar question的一些搜索点,并且在查看the sources of the 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 */
    

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

    请查阅official docs on types以查找固定长度类型的空间。您还可以检查任何类型的pg_column_size()函数的输出,尤其是对于复杂的类型,hstorejsonb

    如果你想对这个主题有更完整的看法,你将不得不深入研究更多细节。