【问题标题】:Sub query on large table with join extremely slow连接极慢的大表上的子查询
【发布时间】:2016-09-04 23:58:07
【问题描述】:

我有以下疑问,

SELECT * FROM users, 
(SELECT * 
FROM mastery 
WHERE champion_rank = 1 
ORDER BY global_rank ASC 
LIMIT 3) as ranks
WHERE users.id = ranks.user_id

Mastery 有 22M 行,users 有 5M 行。上面的查询需要 1800 毫秒才能完成。

问题是下面的子查询在自己运行时需要2.5ms来执行

SELECT * 
FROM mastery 
WHERE champion_rank = 1 
ORDER BY global_rank ASC 
LIMIT 3

从 users 表中检索单个用户需要 2.5 毫秒

SELECT * FROM users WHERE id = 4234523

所以理论上,如果我只是修改我的代码来执行第一个子查询,然后为返回的每一行运行一个额外的查询,整个过程将需要 2.5 + (3 * 2.5) = 10 毫秒来运行。

postgres 肯定在做一些奇怪的事情吗?

数据库结构和索引可以看here

【问题讨论】:

标签: sql postgresql postgresql-performance


【解决方案1】:

您的查询运行缓慢,因为它必须为用户中的 5M 行中的每一行运行排序子查询。

你最好做一个 join single pass,并使用 rank() 窗口函数来过滤你想要的前 3 个:

SELECT users.*, (ranks.mastery).*
FROM (
  SELECT mastery, rank() OVER (ORDER BY global_rank)
  FROM mastery
  WHERE champion_rank = 1
  ) as ranks
JOIN users ON (users.id = ranks.user_id)
WHERE ranks.rank <= 3;

【讨论】:

  • 感谢这工作太棒了,我通过将 mastery.user_id 和 users.id 的数据类型更改为相同来解决这个问题,但这会稍微提高性能。不是 100% 理解它,但我下班回家时会尝试
【解决方案2】:

确定问题,我加入的两个字段的数据类型不同。 Mastery 的用户 id 是数字数据类型,用户 id 是整数数据类型,它必须将每一行转换为新类型。

因此查询时间长。

【讨论】:

  • 如果您将其添加到您的问题中,您可能会在执行计划中看到哪些内容。
  • 我绝对不是 postgres 专家,我确​​实查看了查询的 EXPLAIN ANALYZE,但从中无法直观地找出问题所在,但我认为这主要是由于我对 postgres 缺乏经验
  • 我的意思是:您应该在最初的问题中添加执行计划。很可能有人会立即发现这一点。
猜你喜欢
  • 1970-01-01
  • 2020-04-26
  • 1970-01-01
  • 2013-02-06
  • 1970-01-01
  • 2012-05-03
  • 1970-01-01
  • 2018-02-13
  • 1970-01-01
相关资源
最近更新 更多