【问题标题】:How can I run this except sub-query in one single query?除了子查询之外,我如何在一个查询中运行它?
【发布时间】:2015-11-13 09:58:53
【问题描述】:

我用的是postgreSQL,我有两张表,一张是user,一张是usertasks。

用户有以下字段:userid, username

usertasks 有以下字段:id、taskdate、userid

userid 和 id 是上表的主键

我想查找过去 3 个月内完成的任务少于 3 次的所有用户。 我不能在这里使用 WHERE taskdate>(last3months),因为我需要所有用户,而不仅仅是过去 3 个月内完成任务的用户。 (有些用户可能在 6 个月前完成了他们的任务,但在最近 3 个月内没有做任何任务,所以我也需要这些用户)

我的查询是这样的:

select userid
from users
EXCEPT
select userid from usertasks
where usertasks.taskdate > CURRENT_DATE - INTERVAL '3 months'
group by usertasks.userid having count(id) >= 3

问题: 上面的查询完美运行并返回正确的结果,我也尝试过 NOT IN ,而不是 EXCEPT,这也很好,但问题是我遇到了性能问题,这可以在一个查询中完成而不使用子查询,可以使用连接或任何其他方法完成吗?使用子查询使其变慢。

测试用例是针对 10 万用户和 100 万个任务的,我正在寻找最快的方法..

【问题讨论】:

  • “最快的方法”是:为你的数据模型添加一些结构,例如主键、外键和可能索引。之后,每个适当(且合理)的查询都会产生大致相同的性能。

标签: sql postgresql join group-by


【解决方案1】:

您需要使用havingcase

Select u.user_id
from users u
left join usertask ut
on ut.user_id=u.user_id
group by u.user_id
having count(case when ut.taskdate > CURRENT_DATE - INTERVAL '3 months' then task_id else null end)<3 -- count of tasks in last 3 monthx < 3

【讨论】:

  • "then user_id else null end" 那是任务 ID,不是用户 ID,请编辑并更正,除此之外,我测试了您的查询,它工作正常并给出正确的结果,我会尽快发布有关此查询的性能的信息。
  • @user1735921 更改以反映您的请求,但只要任务 ID 不为空,那么结果应该相同,因为用户 ID 必须为非空才能首先加入.性能方面,这可能是更好的选择之一,我怀疑您是否可以轻松地重写查询以获得更好的性能,而无需更改底层架构。
  • 10 万用户和 100 万个任务并不多,但无论如何处理都不会是即时的。如果您希望它能够很好地扩展,您可以研究减少所用列的位大小的方法(例如,当您的用户少于 16m 时,预先计算一个月的日期或使用 mediumint unsigned INT ID 字段) ,以及适当的索引
  • 另外,如果你只需要user_id,那么你甚至不需要加入2个表,而usertask表就足够了,因为它已经包含你的user_id
  • 性能很棒。它成功了。我正在使用 join,因为 id 不是我想要的唯一东西,所以感谢您的建议。我还需要用户名和所有这些东西。这只是一个例子。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-07-18
  • 1970-01-01
  • 2015-01-08
  • 1970-01-01
相关资源
最近更新 更多