包含大量更新和PostgreSQL的流

包含大量更新和PostgreSQL的流,sql,postgresql,optimization,sql-update,Sql,Postgresql,Optimization,Sql Update,我是一个PostgreSQL优化的新手,我会选择适合的工作,也会选择不适合的工作。所以,我想知道,当我试图使用PostgreSQL进行不合适的工作时,或者它适合它,我应该正确地设置一切 无论如何,我需要一个包含大量频繁更改的数据的数据库 例如,假设一个ISP有很多客户端,每个客户端都有一个会话(PPP/VPN/任何东西),具有两个自描述的频繁更新的属性,即接收的字节和发送的字节。其中有一个表,其中每个会话由具有唯一ID的行表示: CREATE TABLE sessions( id BIG

我是一个PostgreSQL优化的新手,我会选择适合的工作,也会选择不适合的工作。所以,我想知道,当我试图使用PostgreSQL进行不合适的工作时,或者它适合它,我应该正确地设置一切

无论如何,我需要一个包含大量频繁更改的数据的数据库

例如,假设一个ISP有很多客户端,每个客户端都有一个会话(PPP/VPN/任何东西),具有两个自描述的频繁更新的属性,即接收的
字节和发送的
字节。其中有一个表,其中每个会话由具有唯一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)
)
随着会计数据的流动,此表会收到很多更新,如:

-- 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非常繁忙。是否有任何方法来加速所有的事情,或者PASGRESS不完全适合这个任务,我最好认为它不适合这个工作,并把这些计数器像MeCaseDeB一样放到另一个存储中,只使用PrxGRESs来获得相当静态的数据。但我会错过一个很少查询这些数据的功能,例如查找前10名下载者,这不是很好

不幸的是,数据量不能降低很多。ISP会计示例旨在简化解释。真正的问题在于另一个系统,它的结构在某种程度上更难解释


谢谢你的建议

当统计更新发生在某种内存队列中时,您希望将其组装到消息总线上(如果您更雄心勃勃的话)。然后,接收过程会定期汇总这些统计数据更新(可以是每5秒到每小时),具体取决于您想要什么。然后更新接收的
字节数
和发送的
字节数
,这些计数可能代表许多单独的“更新”消息的总和。此外,您应该将多个ID的update语句批处理到单个事务中,确保update语句以与主键相同的相对顺序发出,以防止针对可能正在执行相同操作的其他事务的死锁


通过这种方式,您可以将活动“批处理”到更大的块中,以控制PG数据库上的负载量,还可以将多个并发活动序列化到单个流中(或多个,具体取决于有多少线程/进程正在发布更新)。您根据“周期”调整的权衡是,新鲜度与更新负载的对比。

数据库确实不是收集大量小更新的最佳工具,但由于我不知道您的可查询性和ACID要求,因此我不能推荐其他工具。如果这是一种可接受的方法,那么zzzeek建议的应用程序端更新聚合可以帮助显著降低更新负载

有一种类似的方法,可以让您以一定的性能代价查询更新鲜的数据。创建一个缓冲表,该表可以收集对需要更新的值所做的更改,并将更改插入其中。在事务中定期将表重命名为其他名称,并创建一个新表来代替它。然后在事务中聚合所有更改,对主表进行相应的更新,并截断缓冲表。这样,如果您需要任何数据的一致和新快照,您可以从主表中选择并加入活动和重命名缓冲区表中的所有更改

但是,如果两者都不可接受,您也可以调整数据库以更好地处理繁重的更新负载

要优化更新,请确保PostgreSQL可以用于存储行的更新版本。要执行此操作,请确保频繁更新的列上没有索引,并将更改为低于默认值100%的值。您需要自己找出一个合适的填充因子,因为它在很大程度上取决于工作负载的详细信息及其运行的机器。在autovacuum有机会清理旧的不可见版本之前,fillfactor需要足够低,以使所有更新都适合同一个数据库页面。您可以调整自动真空设置,以在数据库密度和真空开销之间进行权衡。另外,要考虑到任何长事务(包括统计查询)都将保留在事务启动后已更改的元组上。请参阅pg_stat_user_tables视图以查看要调整的内容,特别是n_tup_hot_upd到n_tup_upd和n_live_tup到n_dead_tup之间的关系

大量更新还将产生大量提前写入日志(WAL)负载。调整WAL行为()将有助于降低这一点。特别是,更高的checkpoint_段数和更高的checkpoint_超时可以通过允许内存中发生更多更新来显著降低IO负载。请参阅pg_stat_bgwriter中的checkpoints_timed与checkpoints_req之间的关系,以查看由于达到任一限制而发生的检查点数量。提高共享缓冲区以使工作集适合内存也会有所帮助。检查buffers\u checkpoint和buffers\u clean+buffers\u backend,看看有多少是为了满足检查点要求而写的,而不是刚刚耗尽内存