【问题标题】:How to improve (Postgres)-SQL Query or Table for higher throughput如何改进(Postgresql 查询或表以获得更高的吞吐量
【发布时间】:2021-02-08 14:01:57
【问题描述】:

我必须每 10 分钟查询一次在过去 1、24、724 和 3024 小时内从我们存储每个用户操作一行的数据池中活跃的用户数量.

当用户做某事时,我们将经过哈希处理的 userId、经过哈希处理的操作、时间戳和用户所属的组存储在一个表中。该表用于很多统计目的(例如,决定哪些特征被使用最多,哪些特征导致用户流失等等。)

然而,在此表上最常发生的查询是获取给定时间段内唯一用户的数量。

SELECT
    count(user) as "1m",
    count(*) FILTER (WHERE "timestamp" >= (now() - interval '7 days')::timestamp) as "1w",
    count(*) FILTER (WHERE "timestamp" >= (now() - interval '1 day')::timestamp) as "1d",
    count(*) FILTER (WHERE "timestamp" >= (now() - interval '1 hour')::timestamp) as "1h"
FROM (
    SELECT
        "user" as "user",
        (max(timestamp) + interval '1 hour')::timestamp as "timestamp"
    FROM public.user_activity
    WHERE
        public.user_activity."timestamp" >= (now() - interval '1 month')::timestamp
        AND "system" = 'enterprise'
    GROUP BY  "user"
) as a

所以在子查询中

  • 我们选择时间戳在上个月内且属于给定系统的条目
  • 我们按用户对这些条目进行分组
  • 然后我们选择 userId 和给定分组用户的最后一个时间戳

这个子查询通常会返回 10k 到 100k 的条目(但也应该适用于更多)

然后我们对这个子查询进行另一个查询:

  • 我们将上个月的条目数量统计为用户
  • 我们计算过滤后时间戳比特定时间点更新的条目数量

这个查询在几百万个条目上运行(快速增长)。

如何改进查询以更快地运行?哪些指标是有益的? (使用 AWS RDS 达到了我们 100GB SSD 的 IOPS 限制)

【问题讨论】:

  • 你可能想看看 TimescaleDB(Postgres 的一个插件):docs.timescale.com/latest/using-timescaledb/reading-data - 我认为你的活动日志是 TSDB 的用途......但我不知道不知道 AWS 是否支持这些...
  • count(*) as "1m" 会比count(user) as "1m" 稍快
  • 你能告诉我们 EXPLAIN (ANALYZE, BUFFERS) 的结果吗?然后我们可以看到哪个部分慢,并开始猜测如何改进。
  • 目前执行起来有点困难,因为数据库在我们的 VPC 内,而 VPN 只连接到我们的主办公室,而我们所有的开发人员现在都在家庭办公室。我需要隧道到某台机器并从那里运行它或更改应用程序逻辑以在某处记录该输出
  • @Tobi 你真的需要一个测试数据库,除非你喜欢用头撞墙。

标签: sql postgresql indexing amazon-rds


【解决方案1】:

我会推荐一个关于user_activity(system, timestamp, user) 的索引。

如果索引中的所有行都可见,那么这将覆盖子查询。

对于外部查询无能为力。

但是,我想知道是否像这样表达查询:

SELECT . . .
FROM (SELECT DISTINCT ON (user) "user" as "user",
             (timestamp + interval '1 hour')::timestamp as timestamp
      FROM public.user_activity ua
      WHERE "system" = 'enterprise'
      ORDER BY user, timestamp DESC
     ) ua
WHERE ua.timestamp >= now() - interval '1 month';

(注意:过滤可能会关闭一个小时。要遵循您的确切日期过滤逻辑有点困难。)

user_activity(system, user, timestamp desc) 上使用索引会提供更好的性能。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2011-09-18
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-08-05
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多