20

我不明白 Postgresql(9.2)如何计算列大小(以 kb 为单位),我有这个表:

Table d2:
 Column  |     Type      |
---------+---------------|
 id      | serial        |
 n       | numeric(17,2) |

Table d4:
 Column  |     Type      |
---------+---------------|
 id      | serial        |
 n       | numeric(19,4) |

Table d18:
 Column  |     Type      |
---------+---------------|
 id      | serial        |
 n       | numeric(35,18)|

Table b1:
 Column  |     Type      |
---------+---------------|
 id      | serial        |
 n       | numeric(16,2) |

Table b2:
 Column  |     Type      |
---------+---------------|
 id      | serial        |
 n       | numeric(4,2)  |

我用这段代码填充它们,以便每个表有 10000 行;

$tests = array(2, 4, 18);
foreach($tests AS $n)
{
  $m = number_format(999999999999999.66549865, $n, '.', '');
  $prp_name = "insert_$n";
  $prp = pg_prepare($db, $prp_name, "INSERT INTO d_$n (n) VALUES ($1)");
  for($i = 0; $i < 10000; $i++)
  {
    pg_execute($db, $prp_name, array($m));
  }
}

$prp = pg_prepare($db, 'insert_b1', "INSERT INTO b1 (n) VALUES ($1)");
$m = 16512.67;
for($i = 0; $i < 10000; $i++)
{
  pg_execute($db, 'insert_b1', array($m));
}
$prp = pg_prepare($db, 'insert_b2', "INSERT INTO b2 (n) VALUES ($1)");
$m = 99.36;
for($i = 0; $i < 10000; $i++)
{
  pg_execute($db, 'insert_b2', array($m));
}

现在,我不明白的是怎么可能:

SELECT pg_size_pretty(pg_total_relation_size('d2')) AS size_d2;
 size_d2 
---------
 752 kB

SELECT pg_size_pretty(pg_total_relation_size('d4')) AS size_d4;
 size_d4 
---------
 752 kB

SELECT pg_size_pretty(pg_total_relation_size('d18')) AS size_d18;
 size_d18 
----------
 752 kB

SELECT pg_size_pretty(pg_total_relation_size('b1')) AS size_b1;
 size_b1 
---------
 440 kB

SELECT pg_size_pretty(pg_total_relation_size('b2')) AS size_b2;
 size_b2 
---------
 680 kB

因此,d_* 表具有相同的大小,即使精度(和存储数据的长度)非常不同;

表 b1 比 b2 小,即使精度更高。

pg_total_relazion_size.

我无法在Postgresql 的数据类型文档中找到答案,所以我要在这里问:kb 的大小与数字列的精度有何关系?

我做这个测试是为了决定使用什么精度/比例来在数据库中存储货币类型的 CMS,我希望所有项目的价格只有 1 个精度/比例值(不是总计,比例必须为 2 位小数)。

对于用户而言,我可以存储的小数越多越好(因此当客户要求为特定项目存储 12 个小数时我没有限制),但我想了解此决定将如何影响数据库大小和性能。

4

2 回答 2

36

手册

数值是物理存储的,没有任何额外的前导零或尾随零。因此,列的声明精度和比例是最大值,而不是固定分配。(在这个意义上,数字类型更类似于 varchar(n) 而不是 char(n)。)实际的存储要求是每组四个十进制数字需要两个字节,加上三到八个字节的开销。

pg_total_relation_size函数的结果包括索引。您插入的每个值的正确列大小是:

select pg_column_size(a)
from (values
    (999999999999999.62::numeric(17,2)),
    (999999999999999.6250::numeric(19,4)),
    (999999999999999.625000000000000000::numeric(35,18)),
    (16512.67::numeric(16,2)),
    (99.36::numeric(4,2))
) s(a)
;
 pg_column_size 
----------------
             16
             16
             16
             12
             10

因此,如果您想让用户拥有最多n小数位,只需将其定义为numeric(35, n). 由于不存储尾随零,它将仅使用最多现有小数位数的空间。

于 2013-05-06T15:55:10.360 回答
12

根据 Postgresql doc,整数有 4 个字节,bigint - 8 个字节。的大小

NUMERIC (p, s)

11+(p/2) 字节,其中 p = 精度,s = 比例

存储由数字类型的大小决定,无填充。例如:

SELECT pg_column_size('123'::numeric(21,7)); --8
SELECT pg_column_size('123.1'::numeric(21,7)); --10
SELECT pg_column_size('123.12'::numeric(21,7)); --10
SELECT pg_column_size('123.123'::numeric(21,7)); --10
SELECT pg_column_size('123.1234'::numeric(21,7)); --10
SELECT pg_column_size('123.12345'::numeric(21,7)); --12
SELECT pg_column_size('123.123456'::numeric(21,7)); --12
SELECT pg_column_size('123.1234567'::numeric(21,7)); --12 
于 2016-12-12T08:02:23.490 回答