什么是fillfactor
表的填充因子(fillfactor)是一个介于 10 和 100 之间的百分数。100(完全填充)是默认值。如果指定了较小的填充因子,INSERT操作仅按照填充因子指定的百分率填充表页。每个页上的剩余空间将用于在该页上更新行,这就使得UPDATE有机会在同一页上放置同一条记录的新版本,这比把新版本放置在其它页上更有效。对于一个从不更新的表将填充因子设为100是最佳选择,但是对于频繁更新的表,较小的填充因子则更加有效。该参数对toast表不生效。
PostgresSQL 使用Heap-Only Tuple技术会在旧行与新行之间建立一个链表,这样一来就不需要更新索引了,索引项仍会指向旧行,通过链表可以找到新行。因此Heap-Only Tuple的链表不能跨数据块。
Heap Only Tuple介绍
Heap Only Tuple是 PostgreSQL8.3版中引入的,旨在解决update效率低下的问题。对于一个表,有多个字段,并且有些字段具有索引。此时修改了一个字段的值,由于PostgreSQL MVCC的机制,它会增加了一个tuple,并将前面的tuple标记为dead,而在这个时候,每个tuple的物理地址ctid改变了。而索引存储需要根据ctid的地址来寻找数据。所以修改字段就意味着还需要对索引进行修改,如果表上有很多索引,所有的索引都得修改,这就产生了写放大的问题。使用hot技术后,若所有索引属性都没有被修改(索引键是否修改是在执行时逐行判断的,因此如果一条update修改了某属性,但前后值相同则认为没有修改),且新版本与原来版本存在一个页面上则不会产生新的索引记录,因此这些记录被称为hot(heap only tuple)。
fillfactor与HOT
修改表的fillfactor值,可以影响使用HOT的比例。不使用HOT的update通常需要更新2个数据块,而使用HOT的update只更新1一个数据块。满足以下条件的时候将触发HOT特性:update不修改索引字段;update后,新增的元组在同一个heap page里。
降低fillfactor值的影响
有利影响
- 降低fillfactor值会提升HOT的比例,减少update修改的数据块的数量,因为降低了修改数据块的量,wal的写出的数据量也会同步降低。
- 在update较多的数据库中,降低fillfactor值会减少wal的写出量。
不利影响
- 过小的fillfactor值会浪费存储空间。但如果是频繁更新的数据库中,每个page中还有一部分空间会被dead tuple占据,不一定会比fillfactor设置较小值占用的空间小。
- 过小的fillfactor会降低批量insert的执行速度。
fillfactor对性能的影响
使用benchmarkSQL进行测试,将所有表分别设置fillfactor值为100、90、80进行性能测试。
--benchmarkSQL设置
newOrderWeight=45
paymentWeight=43
orderStatusWeight=4
deliveryWeight=4
stockLevelWeight=4
测试结果如下
fillfactor tpmC tpmTOTAL Transaction Count
100 5699.56 12657.02 254249
90 13132.3 29186.42 586493
80 6636.08 14730.4 296106
--benchmarkSQL设置
newOrderWeight=4
paymentWeight=4
orderStatusWeight=45
deliveryWeight=4
stockLevelWeight=43
测试结果如下
fillfactor tpmC tpmTOTAL Transaction Count
100 4616.39 115648.96 2313732
90 4803.99 120120.56 2403113
80 4306.72 107919.1 2159446
从上面简单的性能测试可以看出,写比例较高时,fillfactor设置的值较小时,比fillfactor值为100(默认值)时性能会好,但不是设置越小越好。读比例较高时,fillfactor设置较低值性能没有太明显提升。
注:修改fillfactor使用的语句如下
ALTER TABLE bmsql_config SET (fillfactor = 90);
ALTER TABLE bmsql_customer SET (fillfactor = 90);
ALTER TABLE bmsql_district SET (fillfactor = 90);
ALTER TABLE bmsql_history SET (fillfactor = 90);
ALTER TABLE bmsql_item SET (fillfactor = 90);
ALTER TABLE bmsql_new_order SET (fillfactor = 90);
ALTER TABLE bmsql_oorder SET (fillfactor = 90);
ALTER TABLE bmsql_order_line SET (fillfactor = 90);
ALTER TABLE bmsql_stock SET (fillfactor = 90);
ALTER TABLE bmsql_warehouse SET (fillfactor = 90);
VACUUM full;
相关语句
--查询表的fillfactor值
SELECT
pc.relname AS ObjectName,pc.reloptions
AS ObjectOptions
FROM pg_class AS pc
INNER JOIN pg_namespace AS pns
ON pns.oid = pc.relnamespace
WHERE pns.nspname = ‘public‘
AND pc.relname = ‘TABLE_NAME‘;
--计算表fillfactor的上限值,fillfactor设置不能高于上限值,对表进行vacuum full之后计算的fillfactor的值最准确
select 1-relpages/reltuples max_fillfactor from pg_class where relname=‘TABLE_NAME‘;