admin

查询内的查询:有没有更好的方法?

sql

在构建更大,更高级的Web应用程序时,我发现自己正在编写极其漫长而复杂的查询。我倾向于在查询中编写很多查询,因为我觉得从PHP一次调用数据库要比多次调用和关联数据更好。

但是,任何对SQL有任何了解的人都对JOINs有所了解。就个人而言,我曾经使用过一JOIN两个,但是当我发现使用子查询时很快就停下来了,因为它对我来说编写和维护起来更加容易和快捷。

通常,我会做一些子查询,其中可能包含相对表中的一个或多个子查询。
考虑以下示例:

SELECT 
  (SELECT username FROM users WHERE records.user_id = user_id) AS username,
  (SELECT last_name||', '||first_name FROM users WHERE records.user_id = user_id) AS name,
  in_timestamp,
  out_timestamp
FROM records
ORDER BY in_timestamp

很少,我将在该WHERE子句之后进行子查询。
考虑以下示例:

SELECT
  user_id,
  (SELECT name FROM organizations WHERE (SELECT organization FROM locations WHERE records.location = location_id) = organization_id) AS organization_name
FROM records
ORDER BY in_timestamp

在这两种情况下,如果我决定使用JOIN?重写查询,我会看到任何改进吗?

作为一个笼统的问题,使用子查询或a的优点/缺点是JOIN什么?一种方法比另一种更正确或被接受吗?


阅读 167

收藏
2021-07-01

共1个答案

admin

最好使用JOIN来分隔[子]查询。
如果子选择(AKA子查询)与外部查询不相关,则优化程序很可能会扫描一次子选择中的表,因为该值不太可能改变。当您具有相关性时(如提供的示例中所示),单遍优化的可能性变得非常小。过去,人们相信会执行相关的子查询,即RBAR-
通过逐行行化。使用JOIN,可以确保在表格上进行一次传递,同时获得相同的结果。

这是对提供的查询的正确重写:

   SELECT u.username,
          u.last_name||', '|| u.first_name AS name,
          r.in_timestamp,
          r.out_timestamp
     FROM RECORDS r 
LEFT JOIN USERS u ON u.user_id = r.user_id
 ORDER BY r.in_timestamp

…因为如果USERS表中不存在user_id,则subselect可以返回NULL 。否则,您可以使用INNER JOIN:

  SELECT u.username,
         u.last_name ||', '|| u.first_name AS name,
         r.in_timestamp,
         r.out_timestamp
    FROM RECORDS r 
    JOIN USERS u ON u.user_id = r.user_id
ORDER BY r.in_timestamp

派生表/内联视图也可以使用JOIN语法。

2021-07-01