我想写一个类似下面的查询
select
username,
(select state from addresses where addresses.username = users.username) email
from users
这适用于Oracle(假设内部查询的结果是唯一的)。但是,这种写作查询方式是否存在性能损失?
答案 0 :(得分:1)
这不是join
本身,而是子查询与主select
语句的串联。
为了使它成为连接(速度更快),您需要以下语法:
select users.username as username, addresses.state as email from users
left join state on (users.username = addresses.username)
在select
语句中使用子查询总是会在DBMS中受到惩罚。将每个子查询视为一个单独的临时表,仅在查询期间存在于内存中,之后DBMS会将其销毁。首先,它为主select
分配内存,然后为子查询表分配更多内存,完整地执行子查询,然后查看两个表以整理结果集。
此外,临时表没有索引优化,因为它们是派生表,并且DBMS已编程为不花时间生成索引(除非DBMS真的非常非常聪明)。
然而,对于join
,内存仅分配给主select
结果表,并使用主结果集填充一次,并添加到join
ed表时搜索(使用为表格设置的任何索引)。
答案 1 :(得分:1)
回到最初的问题,联接是做的数据库。如果他们不能很好地加入,他们就会在市场上失败。因此,您会发现此处讨论的任何变体都会很快。
请注意,“用户”是Oracle中的保留字 - 您可能想要将您的表称为其他内容。另请注意,如果用户的地址中有多条记录,则会在原始公式中引发错误。正常连接只会返回多行。
使用我自己的表格以及合理的索引和数据量,解释计划是:
原始
SELECT STATEMENT ALL_ROWSCost: 226 Bytes: 390,570 Cardinality: 39,057
2 TABLE ACCESS BY INDEX ROWID TABLE X83109.FN_AR_INVOICE Cost: 2 Bytes: 13 Cardinality: 1
1 INDEX UNIQUE SCAN INDEX (UNIQUE) X83109.I_FN_AR_INVOICE Cost: 1 Cardinality: 1
3 TABLE ACCESS FULL TABLE X83109.FN_AR_LINE_ITEM Cost: 226 Bytes: 390,570 Cardinality: 39,057
ANSI Join(如上所述)或传统的Oracle语法,如下所示
select users.username as username, addresses.state as email from users, addresses where users.username = addresses.username;
SELECT STATEMENT ALL_ROWSCost: 377 Bytes: 898,311 Cardinality: 39,057
3 HASH JOIN Cost: 377 Bytes: 898,311 Cardinality: 39,057
1 TABLE ACCESS FULL TABLE X83109.FN_AR_INVOICE Cost: 149 Bytes: 333,788 Cardinality: 25,676
2 TABLE ACCESS FULL TABLE X83109.FN_AR_LINE_ITEM Cost: 226 Bytes: 390,570 Cardinality: 39,057
所以没有太大区别。您应该随意使用联接,但也可以监视性能。