sql - 包含大量更新和 PostgreSQL 的流

标签 sql postgresql optimization sql-update

我是 PostgreSQL 优化方面的新手,我会选择适合它的工作和不适合的工作。因此,我想知道每当我尝试将 PostgreSQL 用于不合适的工作时,或者它是否适合它,我应该正确设置所有内容。

无论如何,我需要一个包含大量数据且经常更改的数据库。

例如,想象一个 ISP,有很多客户端,每个客户端都有一个 session (PPP/VPN/等等),有两个自描述的经常更新的属性 bytes_receivedbytes_sent。它们有一个表,其中每个 session 由具有唯一 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 次)更新,用于具有大量(例如数千个) session 的表,这可能要归功于 MVCC,这使得 PostgreSQL 非常 忙。有什么方法可以加快一切速度,或者 Postgres 并不完全适合这项任务,我最好认为它不适合这项工作,并将这些计数器放在另一个存储中,如 memcachedb,仅将 Postgres 用于相当静态的数据?但我会错过不经常查询此数据的功能,例如查找 TOP10 下载者,这并不是很好。

不幸的是,数据量不能降低太多。 ISP 计费示例都是为了简化说明而想出的。真正的问题在于另一个系统,其结构在某种程度上更难解释。

感谢您的建议!

最佳答案

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

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

但是,如果两者都 Not Acceptable ,您还可以调整数据库以更好地处理繁重的更新负载。

要优化更新,请确保 PostgreSQL 可以使用 heap-only tuples存储行的更新版本。为此,请确保频繁更新的列上没有索引并更改 fillfactor从默认的 100% 降低到更低的值。你需要自己找出一个合适的填充因子,因为它在很大程度上取决于工作负载的细节和它运行的机器。 fillfactor 需要足够低,以便在 autovacuum 有机会清理旧的不可见版本之前,几乎所有更新都适契约(Contract)一个数据库页面。您可以调整 autovacuum 设置以在数据库密度和 vacuum 开销之间进行权衡。此外,请考虑到任何长事务(包括统计查询)都将保留在事务开始后更改的元组。查看 pg_stat_user_tables View 以查看要调整的内容,尤其是 n_tup_hot_updn_tup_upd 以及 n_live_tupn_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 以查看为满足检查点要求而写入的数量与内存不足的情况。

关于sql - 包含大量更新和 PostgreSQL 的流,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/1662912/

相关文章:

java - CPLEX 收入最大化

php - 如何加速数百万个项目的BETWEEN操作?

mysql - 查询中的 SQL 查询返回多个结果

sql - 基于 JOIN 查询创建 Django 模型

Oracle 函数到 PostgreSQL

performance - Chrome DevTools 中帧渲染的空闲时间

Mysql喜欢反向搜索

PostgreSQL - 按 UUID 版本 1 时间戳排序

postgresql - 如何合并时间戳与非空约束postgres

ruby-on-rails - rails : Getting an array of object ids by query/conversion (for comparision)