【问题标题】:PostgreSQL DB size larger than expectedPostgreSQL 数据库大小大于预期
【发布时间】:2021-03-17 18:27:44
【问题描述】:

我有下一个 psql 数据库:

CREATE TABLE "readings33" (
    "uniqueid" BIGSERIAL PRIMARY KEY,
    "uniqueid_sensor" INTEGER NOT NULL,
    "timestamp" TIMESTAMP NOT NULL DEFAULT NULL,
    "value" VARCHAR(15) NOT NULL,
    CONSTRAINT "FK_readings_sensors" FOREIGN KEY ("uniqueid_sensor") REFERENCES "public"."sensors" ("uniqueid") ON UPDATE NO ACTION ON DELETE CASCADE   
);

AFAIK 总大小应该是:

"uniqueid" -> 8 bytes
"uniqueid_sensor" -> 4 bytes
"timestamp" -> 10 bytes
"value" VARCHAR(15) 8 bytes (because my value length for the test is a string with 8 bytes)

所有的总和是 8+4+10+8 = 30 字节,但是当我将 100.000 行写入数据库时​​,这占用了 12.5 Mib,即每行 125 字节。我已经用 10.000 行完成了这个文本,并且关系大致相同......谁能告诉我为什么这个增量是大小??

提前致谢

【问题讨论】:

标签: postgresql heidisql


【解决方案1】:

最后在运行this脚本后发现大小是正确的,不知道HeidiSQL为什么给我一个错误的大小:

WITH cteTableInfo AS 
(
    SELECT 
        COUNT(1) AS ct
        ,SUM(length(t::text)) AS TextLength  
        ,'public.readings'::regclass AS TableName  
    FROM public.readings AS t  
)
,cteRowSize AS 
(
   SELECT ARRAY [pg_relation_size(TableName)
               , pg_relation_size(TableName, 'vm')
               , pg_relation_size(TableName, 'fsm')
               , pg_table_size(TableName)
               , pg_indexes_size(TableName)
               , pg_total_relation_size(TableName)
               , TextLength
             ] AS val
        , ARRAY ['Total Relation Size'
               , 'Visibility Map'
               , 'Free Space Map'
               , 'Table Included Toast Size'
               , 'Indexes Size'
               , 'Total Toast and Indexes Size'
               , 'Live Row Byte Size'
             ] AS Name
   FROM cteTableInfo
)
SELECT 
    unnest(name) AS Description
    ,unnest(val) AS Bytes
    ,pg_size_pretty(unnest(val)) AS BytesPretty
    ,unnest(val) / ct AS bytes_per_row
FROM cteTableInfo, cteRowSize
 
UNION ALL SELECT '------------------------------', NULL, NULL, NULL
UNION ALL SELECT 'TotalRows', ct, NULL, NULL FROM cteTableInfo
UNION ALL SELECT 'LiveTuples', pg_stat_get_live_tuples(TableName), NULL, NULL FROM cteTableInfo
UNION ALL SELECT 'DeadTuples', pg_stat_get_dead_tuples(TableName), NULL, NULL FROM cteTableInfo;

结果:

【讨论】:

  • HeidiSQL 只是总结了pg_table_size() 加上pg_relation_size()。我可能应该添加pg_indexes_size()pg_total_relation_size()
【解决方案2】:

一个timestamp占用8个字节,但是integer后面会有4个字节的填充。一个 8 字节的字符串将占用 9 个字节。

所以行数据占用 33 个字节。连同 23 字节的行标题和大约 60 字节的附加填充。最后,每个 8kB 数据块有一些开销。

如果你得到的远不止这些,那么要么你的测量结果是错误的(你是否包含了主键索引?),或者你的表因数据修改或非标准的fillfactor 设置而变得臃肿。

要测量表格的实际大小,请使用

SELECT pg_table_size('readings33');

要测量包括索引在内的大小,请使用

SELECT pg_total_relation_size('readings33');

【讨论】:

  • 嗨 Laurenz,这些行是从 CSV 文件中导入的,导入后没有修改,并且填充因子是创建表时的默认值。有没有什么应用可以分析问题出在哪里??表的大小是用 HeidiSQL 测量的,不知道具体是做什么的,索引从 1 开始。
  • 我已在答案中添加了查询。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-11-21
  • 1970-01-01
  • 1970-01-01
  • 2023-03-11
相关资源
最近更新 更多