【问题标题】:Select random rows according to a given criteria PostgreSQL根据给定条件 PostgreSQL 选择随机行
【发布时间】:2020-04-09 16:06:17
【问题描述】:

我有表user 一千万行。它有字段:id int4 primary keyrating int4country varchar(32)last_active timestamp。它在标识符上有差距。 任务是为给定的国家随机选择五个用户,这些用户在过去两天内活跃并且在给定范围内具有评级。 有没有比下面的查询更快地选择它们的棘手方法?

SELECT id
FROM user
WHERE last_active > '2020-04-07'
    AND rating between 200 AND 280
    AND country = 'US'
ORDER BY random()
LIMIT 5

它想到了这个查询:

SELECT id
FROM user
WHERE last_active > '2020-04-07'
    AND rating between 200 AND 280
    AND country = 'US'
    AND id > (SELECT random()*max(id) FROM user)
ORDER BY id ASC
LIMIT 5

但问题是有很多非活动用户的标识符值很小,大多数新用户都在 id 范围的末尾。所以,这个查询会过于频繁地选择一些用户。

【问题讨论】:

  • 请显示当前计划的解释(分析,缓冲区)。加快速度的最佳方法可能是使现有查询更快,而不是试图找到不太正确的查询。
  • 这是来自生产数据库的output。我已经发现它是在默认设置下运行的。我还从查询中排除了 country 列,因为它仅在开发代码中。

标签: sql postgresql random


【解决方案1】:

根据 EXPLAIN 计划,您的表很大。每页大约 2 行。要么非常臃肿,要么行本身非常宽。

获得良好性能的关键可能是让它使用仅索引扫描,方法是创建一个包含查询中引用的所有 4 列的索引。测试相等性的列应该放在第一位。之后,您必须根据您认为更具选择性的任何一个在两个范围或不等式查询列(“last_active”或“rating”)之间进行选择。然后将另一个范围或不等式和 id 列添加到末尾,以便可以使用仅索引扫描。所以也许create index on app_user (country, last_active, rating, id)。这可能已经足够了。

您也可以在这些相同的列上尝试使用 GiST 索引。这具有理论上的优势,即两个范围或不等式限制可以一起用于定义要查看的索引页面。但在实践中,GiST 索引的开销非常高,而且这种开销可能会超过理论上的收益。

如果以上还不够好,您可以尝试分区。但具体如何做到这一点应该基于您的应用程序的整体视图,而不仅仅是一个查询。

【讨论】:

  • 感谢您的努力。我会考虑如何在应用程序级别解决任务,而不是在 dbms 上。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-02-15
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多