我有一个相当大的数据集(数百万行)。我在向某个查询引入“独特”概念时遇到问题。 (我将 unique 放在引号中,因为这可以由 posgtres 关键字 DISTINCT 或“group by”形式提供)。
非唯一搜索需要 1ms - 2ms ;所有引入“独特”概念的尝试都已将其增长到 50,000ms - 90,000ms 范围。
我的目标是根据事件流中最近出现的情况来显示最新资源。
我的非独特查询本质上是这样的:
SELECT
resource.id AS resource_id,
stream_event.event_timestamp AS event_timestamp
FROM
resource
JOIN
resource_2_stream_event ON (resource.id = resource_2_stream_event.resource_id)
JOIN
stream_event ON (resource_2_stream_event.stream_event_id = stream_event.id)
WHERE
stream_event.viewer = 47
ORDER BY event_timestamp DESC
LIMIT 25
;
我使用 DISTINCT、GROUP BY 和 MAX(event_timestamp) 尝试了许多不同形式的查询(和子查询)。问题不在于得到一个有效的查询,而在于得到一个在合理的执行时间内有效的查询。查看每一项的 EXPLAIN ANALYZE 输出,一切都依赖于索引。问题似乎是,在尝试对结果进行重复数据删除时,postges 必须将整个结果集组装到磁盘上;由于每个表有数百万行,这成为瓶颈。
--
更新
这是一个工作组查询:
EXPLAIN ANALYZE
SELECT
resource.id AS resource_id,
max(stream_event.event_timestamp) AS stream_event_event_timestamp
FROM
resource
JOIN resource_2_stream_event ON (resource_2_stream_event.resource_id = resource.id)
JOIN stream_event ON stream_event.id = resource_2_stream_event.stream_event_id
WHERE (
(stream_event.viewer_id = 57) AND
(resource.condition_1 IS NOT True) AND
(resource.condition_2 IS NOT True) AND
(resource.condition_3 IS NOT True) AND
(resource.condition_4 IS NOT True) AND
(
(resource.condition_5 IS NULL) OR (resource.condition_6 IS NULL)
)
)
GROUP BY (resource.id)
ORDER BY stream_event_event_timestamp DESC LIMIT 25;
查看查询计划程序(通过 EXPLAIN ANALYZE),似乎添加 max+groupby 子句(或不同的子句)会强制顺序扫描。这大约花费了计算机时间的一半。已经有一个包含每个“条件”的索引,我尝试创建一组索引(每个元素一个)。没有工作。
无论如何,差异在 2ms 和 72,000ms 之间
最佳答案
通常,distinct on
是为每项内容获取一行的最有效方法。我建议尝试:
SELECT DISTINCT ON (r.id) r.id AS resource_id, se.event_timestamp
FROM resource r JOIN
resource_2_stream_event r2se
ON r.id = r2se.resource_id JOIN
stream_event se
ON r2se.stream_event_id = se.id
WHERE se.viewer = 47
ORDER BY r.id, se.event_timestamp DESC
LIMIT 25;
resource(id, event_timestamp)
上的索引可能有助于提高性能。
编辑:
您可以尝试使用 CTE 来获得您想要的结果:
WITH CTE as (
SELECT r.id AS resource_id,
se.event_timestamp AS stream_event_event_timestamp
FROM resource r JOIN
resource_2_stream_event r2se
ON r2se.resource_id = r.id JOIN
stream_event se
ON se.id = r2se.stream_event_id
WHERE ((se.viewer_id = 57) AND
(r.condition_1 IS NOT True) AND
(r.condition_2 IS NOT True) AND
(r.condition_3 IS NOT True) AND
(r.condition_4 IS NOT True) AND
( (r.condition_5 IS NULL) OR (r.condition_6 IS NULL)
)
)
)
SELECT resource_id, max(stream_event_event_timestamp) as stream_event_event_timestamp
FROM CTE
GROUP BY resource_id
ORDER BY stream_event_event_timestamp DESC
LIMIT 25;
Postgres 实现了 CTE。因此,如果没有那么多匹配项,可以通过使用 CTE 索引来加快查询速度。
关于sql - 优化 postgres 中的大 "distinct"选择,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/26005683/