PostgreSQL仅附加日志的最新条目

时间:2019-05-12 04:29:28

标签: sql postgresql

我想将用户设置存储在Postgresql数据库中。 我想保留其设置的完整历史记录,并且还能够查询给定用户的最新设置。

我尝试将设置存储在这样的表中:

CREATE TABLE customer (
    customer_id INTEGER PRIMARY KEY,
    name VARCHAR NOT NULL  
);

CREATE TABLE customer_settings (
    customer_id INTEGER REFERENCES customer NOT NULL,
    sequence INTEGER NOT NULL, -- start at 1 and increase, set by the application
    settings JSONB NOT NULL,
    PRIMARY KEY(customer_id, sequence)
);

因此,customer_settings是每个客户的仅追加日志。

然后查询最新设置,我使用了一个长查询,它将执行一个子查询来为给定的sequence选择最大值customer_id,然后为该ID选择设置。

这很尴尬!我想知道是否有更好的方法?我可以使用视图还是触发器来创建第二张表latest_customer_settings ??

3 个答案:

答案 0 :(得分:2)

您可以进行查看。要获得Postgres中多个客户的设置,我建议:

select distinct on (customer_id)
from customer_settings cs
order by customer_id, sequence desc;

对于此查询,我建议在customer_settings(customer_id, sequence desc)上添加一个索引。

此外,如果可以为所有客户处理一个总的序列号,则可以让Postgres生成序列。

CREATE TABLE customer_settings (
    customer_settings_id bigserial primary key,
    customer_id INTEGER REFERENCES customer NOT NULL,
    settings JSONB NOT NULL
); 

然后,应用程序不需要设置sequence号。您只需将customer_idsettings插入表中即可。

让应用程序维护此信息有一些缺点。首先,应用程序必须先读取数据库,然后才能将任何内容插入表中。其次,如果多个线程同时更新表(在这种情况下,是同一位客户),则可以具有竞争条件。

答案 1 :(得分:0)

您可以使用row_number()窗口功能,它将帮助您获取每个客户的最新设置

with cte as (select cs.*,
row_number() over(partition by c.customer_id order by sequence desc) rn
  from customer c join customer_settings cs on c.customerid=cs.customerid
    ) select * from cte where rn=1

答案 2 :(得分:0)

假设您只需要给定用户的最新日志,并且假设sequence一直在增加并且是唯一的,那么实际上您只需要一个简单的查询:

SELECT *
FROM customer_settings
WHERE customer_id = 123
ORDER BY sequence DESC
LIMIT 1;

如果您想花一些时间来创建更好的日志记录框架,请尝试研究MDC之类的东西(映射诊断上下文,see here)。使用MDC,每个日志语句都使用完全唯一的标识符写出,该标识符也将在响应头或正文中发送。然后,将后端与前端或使用者之间的异常关联起来变得容易又万无一失。