sql - 优化 postgres 中的大 "distinct"选择

标签 sql postgresql

我有一个相当大的数据集(数百万行)。我在向某个查询引入“独特”概念时遇到问题。 (我将 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/

相关文章:

sql - 使用 VBA 运行多个 SQL 查询 (Oracle) - 为什么这么慢?

两个日期和两次之间的mySQL查询

sql - 在 postgres 中解码等效项

postgresql - alter table add column default 并对每一行执行default

c# - 在 npgsql 准备好的命令中替换准备好的查询参数的问题

php - mysql 子查询有多于一列

sql - 在 Case 语句中使用多个条件

MYSQL (NOT IN) 查询很慢

json - 使用 Postgres 在多列上调用 to_json

sql - 如何检索特定行的列值