我试图找出PostgreSQL在磁盘上施加了多大的压力,结果到目前为止令人沮丧。请看一下方法论,显然我错过了某些东西或以错误的方式计算数字。
PostgreSQL 9.6.0-1.pgdg16.04 + 1在一个单独的LXC容器内运行,Ubuntu 16.04.1 LTS(内核版本4.4.0-38-generic,ext4文件系统在SSD之上),只有一个我运行测试的客户端连接。
我禁用autovacuum
以防止不必要的写入。
写入字节的计算是通过以下命令完成的,我想查找所有PostgreSQL进程(包括WAL编写器)写入的总字节数:
pgrep postgres | xargs -I {} cat /proc/{}/io | grep ^write_bytes | cut -d' ' -f2 | python -c "import sys; print sum(int(l) for l in sys.stdin)"
使用#
符号我标记了一个数据库命令,→
我在数据库命令之后标记了write_bytes sum的结果。测试用例很简单:只有一个int4
列的表填充了10000000个值。
在每次测试之前,我运行一组命令来释放磁盘空间并阻止其他写入:
# DELETE FROM test_inserts;
# VACUUM FULL test_inserts;
# DROP TABLE test_inserts;
正如文档所述,UNLOGGED
表中的更改不会写入WAL日志,因此它是一个很好的开始点:
# CREATE UNLOGGED TABLE test_inserts (f1 INT);
→ 1526276096
# INSERT INTO test_inserts SELECT generate_series(1, 10000000);
→ 1902977024
差异是 376700928字节(~359MB),这有点合理(千万个4字节整数+行,页面和其他成本),但仍然看起来有点太多,几乎是实际数据量的10倍。
# CREATE UNLOGGED TABLE test_inserts (f1 INT PRIMARY KEY);
→ 2379882496
# INSERT INTO test_inserts SELECT generate_series(1, 10000000);
→ 2967339008
差异是 587456512字节(~560MB)。
# CREATE TABLE test_inserts (f1 INT);
→ 6460669952
# INSERT INTO test_inserts SELECT generate_series(1, 10000000);
→ 7603630080
差异已经 1142960128字节(~1090MB)。
# CREATE TABLE test_inserts (f1 INT PRIMARY KEY);
→ 12740534272
# INSERT INTO test_inserts SELECT generate_series(1, 10000000);
→ 14895218688
现在差异是 2154684416字节(~2054MB),大约30秒后写入额外的100MB。
对于这个测试用例,我按流程进行了细分:
Process | Bytes written
/usr/lib/postgresql/9.6/bin/postgres | 0
\_ postgres: 9.6/main: checkpointer process | 99270656
\_ postgres: 9.6/main: writer process | 39133184
\_ postgres: 9.6/main: wal writer process | 186474496
\_ postgres: 9.6/main: stats collector process | 0
\_ postgres: 9.6/main: postgres testdb [local] idle | 1844658176
有关如何衡量我正确寻找的价值观的任何想法和建议?也许它是一个内核错误?或者PostgreSQL真的做了这么多的写作?
编辑:要仔细检查write_bytes是什么意思,我写了一个简单的python script证明,这个值是实际写入的字节值。
编辑2:对于PostgreSQL 9.5测试用例#1显示362577920字节,测试#4显示2141343744字节,因此它与PG版本无关。
编辑3: Richard Huxton提到Database Page Layout文章,我想详细说明:我同意存储费用,包括24个字节的行标题, 4个字节的数据本身甚至4个字节用于数据对齐(通常为8个字节),每行提供32个字节,并且每行有大约320MB的行数,这是我用测试#1得到的。 我可以假设在这种情况下,主键应该与数据大小相同,并且测试#4(数据和PK)都将写入WAL。这给了360MB x 4 = 1.4GB,这比我得到的结果要差。