我有一个相当大的数据集(数百万行)。我在向某个查询引入“独特”概念时遇到了麻烦。 (我在引号中加上不同的内容,因为这可以通过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之间
答案 0 :(得分:2)
通常,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的索引来加速查询。