我有一个文档管理系统,可以在历史表中记录所有历史事件。我被要求能够在给定日期为给定客户提供状态为 5 的最旧 doc_id。该表看起来像这样(为简单起见被截断):
doc_history:
id integer
doc_id integer
event_date timestamp
client_id integer
status_id integer
client_id 和 status_id 列是事件发生后文档的值。这意味着由 doc_id 定义的文档的最大历史事件行将匹配文档表中的相同列。通过特定事件日期限制事件,您可以查看当时文档的值。因为这些值不是静态的,所以我不能简单地搜索 status_id 为 5 的特定 client_id,因为找到的结果可能与文档的 max(id) 不匹配。希望这有点道理。
我发现工作但很慢的是以下内容:
select
t.*
from
(select
distinct on (doc_id),
*
from
doc_history
where
event_date <= '2013-02-17 23:59:59'
order by
doc_id, id desc) t
where
t.client_id = 9999 and
t.status_id = 5
limit 1;
基本上,我在给定的最大事件日期之前获取特定文档 ID 的最大 ID,然后验证该最大历史项目是否已分配给给定客户端,状态设置为 5。
以我的方式这样做的缺点是我正在扫描所有客户的所有历史记录以获取它们的最大值,然后找到我正在寻找的一个客户和状态。截至目前,这扫描了大约 1506 万行,在我的开发服务器上大约需要 90 秒(这不是很快)。
为了使事情变得更复杂,我需要在前一周的每一天都这样做,或者每次运行总共七次。此外,系统中的所有单据都以状态 5 开头,表示新单据。这使得该查询将只返回为该客户端输入的第一个文档:
select * from doc_history where client_id = 9999 and
status_id = 5 and
event_date <= '2013-02-17 23:59:59'
order by id limit 1;
我希望做的是扫描,直到找到与特定客户端和状态值匹配的特定文档的最大历史记录,而不必首先找到所有客户端的所有文档 ID 的最大 ID。我不知道这是否可以通过窗口函数(分区)或我目前没有看到的其他逻辑来完成。
doc_history 表中的事件之一的示例:
# select id, doc_id, event, old_value, new_value, event_date, client_id, status_id from doc_history where doc_id = 9999999 order by id;
id | doc_id | event | old_value | new_value | event_date | client_id | status_id
----------+---------+-------+-----------+-----------+----------------------------+-----------+-----------
25362415 | 9999999 | 13 | | | 2013-02-14 11:49:50.032824 | 9999 | 5
25428192 | 9999999 | 15 | | | 2013-02-18 11:15:48.272542 | 9999 | 5
25428193 | 9999999 | 7 | 5 | 1 | 2013-02-18 11:15:48.301377 | 9999 | 1
事件 7 是状态改变,新旧值显示从 5 变为 1,这在 status_id 列中有所体现。对于小于或等于 2013-02-17 23:59:59 的 event_date,上述记录将是 status_id 为 5 的最旧的“NEW”文档,但在 2013 年 2 月 17 日之后就没有了。