【问题标题】:Does using a query inside a select statement execute that query for every row?在 select 语句中使用查询是否会为每一行执行该查询?
【发布时间】:2020-04-06 02:57:11
【问题描述】:

我使用 Postgres 编写了以下查询:

SELECT 
    *,
    CASE 
        WHEN
            (SELECT count(*) FROM applications WHERE applications.user_id = 774 AND applications.job_id = jobs.id) > 0
        THEN 1 
        ELSE 0 
    END 
    AS has_applied 
FROM jobs

它从我的数据库中选择所有作业并运行检查以查看当前登录的用户(在本例中 ID 为 774)是否已申请该作业。

我看到我的数据库 GUI 中只运行了一个查询,但这不是必须为 jobs 表中的每一行运行嵌套查询吗?

有没有更好的方法来写这个?或者这似乎应该通过比较来自两个单独查询的数据集来完成?

【问题讨论】:

  • "这不是必须为每一行运行嵌套查询" 不,它只需要返回 SQL 描述的行。阅读有关一般性和 DBMS 的关系查询实现/优化的基础知识。这些是常见问题解答。在考虑发布之前,请阅读手册和谷歌任何错误消息或您的问题/问题/目标的许多清晰、简洁和精确的措辞,有和没有您的特定字符串/名称和站点:stackoverflow.com 和标签;阅读许多答案。如果您发布问题,请使用一个短语作为标题。反映你的研究。请参阅How to Ask 和投票箭头鼠标悬停文本。
  • 不清楚您所说的“在我的数据库 GUI 中只看到一个查询”是什么意思。但是这里有一个查询表达式,其中包含一个子查询作为子表达式,因此无论在查询表达式转换为代码后,任何一段实现代码重复运行的频率如何,都只会运行一个查询。了解 SQL EXPLAIN、查询计划等。
  • 查看执行计划。如果将其重写为左连接,我不会感到惊讶

标签: sql postgresql query-performance


【解决方案1】:

你可以用左连接来写这个:

SELECT
    j.*,
    CASE WHEN COUNT(CASE WHEN a.user_id = 774 THEN 1 END) > 0
         THEN 1 ELSE 0 END AS has_applied
FROM jobs j
LEFT JOIN applications a
    ON j.id = a.job_id
GROUP BY
    j.id;

请注意,上面的 GROUP BY 语法实际上在 Postgres 上有效,假设 jobs.id 是该表的主键。在这种情况下,jobs.* 是在功能上都依赖于jobs.id 的列。

【讨论】:

  • 这让我有点理解,但现在我明白了。惊人的!我必须做的唯一调整是将COUNT(...) > 1 更改为大于0。就我而言,一个用户只能申请一次工作,所以我认为COUNT(...) = 1 也可以。
  • Nvm,现在我看到对于我的情况,这部分可以缩短为CASE WHEN a.user_id = 774。好东西要知道,很好的解决方案!
【解决方案2】:

你可以简单地做LEFT JOIN

SELECT j.*, (CASE WHEN a.job_id IS NULL THEN 0 ELSE 1 END) AS has_applied
FROM jobs j LEFT JOIN
     applications a
     ON a.job_id = j.id AND a.user_id = 774;

【讨论】:

  • 请注意,此解决方案假定给定用户最多一次申请某个职位。否则,此方法可能会为给定作业生成重复记录。
  • 看起来这也有效。可能是我最终将使用的那个,因为我们在应用程序的业务规则中只强制申请一次工作,但是,我没有在我的问题中指定这一点。如果有什么变化,最好有两种解决方案。
  • @TimothyFisher 。 . .如果人们可以多次申请同一个工作,那么这可能会返回重复。我强烈推荐 exists 做你想做的事。
【解决方案3】:

强烈推荐使用EXISTS。您可以在 Postgres 中将该值作为布尔值返回,因此:

SELECT j.*,
       (EXISTS (SELECT 1
                FROM applications a
                WHERE a.job_id = j.id AND a.user_id = 774 
       ) as has_applied
FROM jobs j;

使用applications(job_id, user_id) 上的索引应该没有更快的方法来处理查询。

【讨论】:

    猜你喜欢
    • 2013-01-23
    • 2014-03-03
    • 2019-12-30
    • 2019-08-08
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多