无论如何,我需要一个包含大量经常变化的数据的数据库.
例如,假设一个ISP,拥有大量客户端,每个客户端都有一个会话(PPP / VPN /无论如何),有两个自描述频繁更新的属性bytes_received和bytes_sent.有一个表格,每个会话由一个具有唯一ID的行表示:
CREATE TABLE sessions( id BIGSERIAL NOT NULL,username CHARACTER VARYING(32) NOT NULL,some_connection_data BYTEA NOT NULL,bytes_received BIGINT NOT NULL,bytes_sent BIGINT NOT NULL,CONSTRAINT sessions_pkey PRIMARY KEY (id) )
并且随着会计数据的流动,此表会收到许多UPDATE,如下所示:
-- There are *lots* of such queries! UPDATE sessions SET bytes_received = bytes_received + 53554,bytes_sent = bytes_sent + 30676 WHERE id = 42
当我们收到一个永无止境的流,有很多(比如每秒1-2次)的更新,对于一个有很多(几千个)会话的表,可能要归功于MVCC,这使得Postgresql非常繁忙.有什么方法可以加速一切,或者Postgres不完全适合这个任务,我最好认为它不适合这个工作,并将这些计数器放到另一个存储器,如memcachedb,使用Postgres仅用于相当静态的数据?但我会错过不经常查询这些数据的能力,例如找到TOP10下载器,这不是很好.
不幸的是,数据量不能降低太多. ISP会计示例全部用于简化说明.真正的问题在于另一个系统,这种结构在某种程度上难以解释.
谢谢你的建议!
有一种类似的方法可以为您提供耐用性和以某些性能成本查询更新数据的能力.创建一个缓冲表,可以收集需要更新的值的更改并在其中插入更改.在事务中定期将表重命名为其他内容并创建一个新表来代替它.然后在事务中聚合所有更改,对主表执行相应的更新并截断缓冲表.这样,如果您需要从主表中选择的任何数据的一致且全新的快照,并加入来自活动和重命名的缓冲区表的所有更改.
但是,如果两者都不可接受,您还可以调整数据库以更好地处理大量更新负载.
要优化更新,请确保Postgresql可以使用heap-only tuples来存储行的更新版本.为此,请确保经常更新的列上没有索引,并将fillfactor更改为默认值100%以下的值.您需要自己确定合适的填充因子,因为它很大程度上取决于工作负载及其运行的计算机的详细信息. fillfactor需要足够低,使得所有更新都适合同一数据库页面,然后autovacuum才有机会清理旧的不可见版本.您可以调整autovacuum设置以在数据库密度和真空开销之间进行权衡.此外,请考虑任何长事务(包括统计查询)将保留在事务开始后已更改的元组.请参阅pg_stat_user_tables视图以查看要调整的内容,尤其是n_tup_hot_upd与n_tup_upd和n_live_tup与n_dead_tup的关系.
大量更新还会产生大量写入日志(WAL)负载.调整WAL行为(docs for the settings)将有助于降低这一点.特别是,更高的checkpoint_segments数和更高的checkpoint_timeout可以通过允许在内存中进行更多更新来显着降低IO负载.请参阅pg_stat_bgwriter中checkpoints_timed与checkpoints_req的关系,以查看有多少检查点发生,因为已达到任一限制.提升你的shared_buffers以使工作集适合内存也会有所帮助.检查buffers_checkpoint与buffers_clean buffers_backend以查看为满足检查点要求而不是内存耗尽而编写的数量.