当我建立更大,更先进的Web应用程序,我发现自己写很长的和复杂的查询。 我倾向于在查询中编写查询了很多,因为我觉得自己做的数据库一个呼叫从PHP是不是让数和数据关联更好。
然而,谁知道什么SQL谁知约JOIN
秒。 就个人而言,我已经使用了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
?
随着越来越多的毯子问题,什么是使用子查询或优势/劣势JOIN
? 是一种方法更正确或比其他接受?
连接是优选的以分离[子]查询。
如果子选择(AKA子查询)不相关的外部查询,这是非常有可能的优化器将扫描表(S)的子查询一次,因为该值是不可能改变的。 当你有关系,就像在所提供的示例中,单次优化的可能性变得不太可能。 在过去,它被认为相关子查询执行,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
......因为子查询可以返回NULL,如果USER_ID不在存在USERS
表。 否则,你可以使用一个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语法。
在简单的情况下,查询优化器应该能够产生相同的计划,一个简单连接与一个简单的分选。
但在一般情况(在适当情况下),你应该有利于加入了子选择。
此外,应避免相关子查询(其中内表达指的是外的查询),因为它们是有效的for循环在for循环内)。 在大多数情况下,相关子查询可以写成一个连接。
一)我想通过指出的是,两者并不一定是可以互换的开始。 嵌套因为你已经要求那里是0或1的匹配值,否则,你会得到一个错误。 联接看跌期权没有这样的要求,可以排除该记录或引进更多的取决于您的数据和连接的类型。
b)在性能方面,则需要检查查询计划,但您的嵌套的例子不太可能是更有效的比表连接。 通常,子查询每行执行一次但这在很大程度上取决于你的数据库,唯一约束,foriegn键,不为空等等也许DB可以更有效地重写上,但连接可以使用更广泛的技术,推动来自不同数据表等,因为他们做不同的事情(虽然你可能不取决于你的数据在输出中观察到的任何差异)。
C)大多数DB意识到程序员,我知道会看你的嵌套查询和重写使用联接,受制于数据是合适的“干净”。
d)关于“正确” - 我赞成联接您的数据备份与正确的约束条件在必要时(如一个唯一的用户ID)。 你作为一个人可以做出某些假设,但DB引擎不能,除非你告诉它。 它知道的越多,更好的工作它(和你)可以做。
加入在大多数情况下,将更加快捷。
让我们用一个例子。
让我们用你的第一个查询:
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
现在考虑我们有100条记录中记录和100条记录的用户。(假设我们没有对user_ID的指数)
因此,如果我们理解你的算法,它说:对于每个记录扫描所有100个记录的用户找出用户名扫描所有100个记录的用户找出姓氏和名字
因此,它就像我们扫描用户表100 * 100 * 2的时间。 是否真的值得。 如果我们考虑USER_ID它会使事情更好的指标,但它仍然是值得的。
现在考虑一个连接(嵌套循环几乎会产生相同的结果同上,但考虑散列连接):它的喜欢。 使用户哈希映射。 对于每个记录查找HashMap中的映射记录。 这将是肯定更多更快然后循环,找到一个记录。
所以很明显,加入应该是有利的。
注意:使用100记录的例子,可能产生相同的计划,但这个想法是分析它如何影响性能。