将日志存储在 postgres 数据库中作为文本与 json 类型

Storing logs in postgres database as text vs json type

假设我们要创建一个 table 来将用户 activity 的日志存储在数据库中。我可以想到两种方法:

  1. A table 每个日志条目都有一行,其中包含日志 ID、用户的外键和日志内容。这样,我们将为发生的每个 activity 单独一行。

  2. A table 每个唯一用户(用户的外键)和日志 ID 的 activity 有一行。我们可以有一个 json 类型的列来存储与每个用户关联的日志。每次出现 activity 时,我们都可以获取关联的日志条目并通过向其附加新的 activity 来更新其 JSON 列。

方法 1 提供了一种无需更新旧日志条目即可添加新日志条目的简洁方法。但是查询这样一个 table 来获取用户的 activity 将查询整个 table.

方法 2 增加了添加新用户的复杂性 activity,因为我们必须获取和更新 JSON 对象,但查询只会 return 一行。

我需要帮助来了解一种方法是否明显优于另一种方法。

如果您记录了很多更改,就属性而言,我会创建一个 table 具有:

log_iduser_id (fk) 和 log 采用 json 格式,每行为一行 activity。

如果您为 table 编制索引,则不会出现性能问题。在 postgresql 中,您可以在 json 列内的字段上建立索引。

每次更新后,随着列大小的增加,方法 2 的更新速度会变慢。另外,查询会比较复杂。

数据库经过优化,可以从大 table 中存储和检索小行。因此,寻求第一个解决方案。索引使连接如此快速。

将一个用户的所有数据集中到单个 JSON 对象中不会让您满意:每次更新都必须读取、修改和写入整个 JSON,这在以下方面效率不高全部.

还要考虑一个可以parse semi-structured data into database columns的日志框架,例如Serilog。

否则我也会推荐你的选项“1”,每个日志一行,索引在 user_id,但建议在你的列中添加时间戳,以便查询引擎可以按顺序排序在必须为时间戳解析 json 本身之前发生的事件:

CREATE TABLE user_log
(
    log_id             bigint, -- (PRIMARY KEY),
    log_ts             timestamp NOT NULL DEFAULT(now()),
    user_id            int NOT NULL, --REFERENCES users(user_id),
    log_content        json
);
CREATE INDEX ON user_log(user_id);

SELECT user_id, log_ts, log_content => 'action' AS user_action FROM user_log WHERE user_id = ? ORDER BY log_ts;