【发布时间】:2023-01-20 03:16:13
【问题描述】:
我有以下内容仅追加psql中的表:
CREATE TABLE IF NOT EXISTS data (
id UUID DEFAULT gen_random_uuid () PRIMARY KEY,
test_id UUID NOT NULL,
user_id UUID NOT NULL,
completed BOOL NOT NULL DEFAULT False,
inserted_at TIMESTAMPTZ NOT NULL DEFAULT (NOW() AT TIME ZONE 'UTC'),
);
CREATE INDEX some_idx ON data (user_id, test_id, inserted_at DESC);
CREATE INDEX some_idx2 ON data (test_id, inserted_at DESC);
对于给定的test_id,单个user_id 可能有多个条目,但只有一个可以是completed(completed 条目也是最后一个)。
我正在查询给定的 test_id。我需要的是过去一周中每一天的类似时间序列的数据。对于每一天,我应该有以下内容:
-
全部的- 唯一用户的总条目 WHERE
inserted_at < "day" -
完全的-
inserted_at < "day"唯一用户的总完成条目
最终,total 和 completed 就像计数器,我只是想获取过去一周每一天的值。例如:
| date | total | completed |
|------------|-------|-----------|
| 2022.01.19 | 100 | 50 |
| 2022.01.18 | 90 | 45 |
| ... | | |
什么是具有高效查询计划的查询?我可以考虑添加新索引或修改现有索引。
PS:我这里有一个工作版本:
SELECT date, entered, completed
FROM (
SELECT d::date AS date
FROM generate_series('2023-01-12', now(),INTERVAL '1 day') AS d
) AS dates
cross join lateral (
SELECT COUNT(DISTINCT user_id) AS entered,
COUNT(1) FILTER (WHERE completed) AS completed // no need for distinct as completed is guaranteed to be once per user
FROM data
WHERE
test_id = 'someId' AND
inserted_at < dates.date
) AS vals
我不认为这是一个好的/高性能的解决方案,因为它会在每次横向连接迭代时重新扫描表。这是查询计划:
+---------------------------------------------------------------------------------------------------------------------------->
| QUERY PLAN >
|---------------------------------------------------------------------------------------------------------------------------->
| Nested Loop (cost=185.18..185218.25 rows=1000 width=28) (actual time=0.928..7.687 rows=8 loops=1) >
| -> Function Scan on generate_series d (cost=0.01..10.01 rows=1000 width=8) (actual time=0.009..0.012 rows=8 loops=1) >
| -> Aggregate (cost=185.17..185.18 rows=1 width=16) (actual time=0.957..0.957 rows=1 loops=8) >
| -> Bitmap Heap Scan on data (cost=12.01..183.36 rows=363 width=38) (actual time=0.074..0.197 rows=779 loops>
| Recheck Cond: ((test_id = 'someId'::uuid) AND (inserted_at < (d.d)::date)) >
| Heap Blocks: exact=629 >
| -> Bitmap Index Scan on some_idx2 (cost=0.00..11.92 rows=363 width=0) (actual time=>
| Index Cond: ((test_id = 'someId'::uuid) AND (inserted_at < (d.d)::date>
| Planning Time: 0.261 ms >
| Execution Time: 7.733 ms >
+---------------------------------------------------------------------------------------------------------------------------->
我确定我在这里缺少一些方便的功能,这些功能会有所帮助。感谢所有帮助:祈祷:
【问题讨论】:
-
您可以使用带范围的窗口函数来获得相同的结果,而无需疯狂的交叉连接。
-
@霍根谢谢!我以前从未在 psql 中使用过窗口函数,所以我需要试验一下。你知道它的大致外观吗?
-
是的...给我几分钟
标签: sql postgresql