2017-02-28 134 views
-4

我总是看到人们使用这两种方式来连接两个或多个表。从两个表中选择joid vs加入两个选择

select * 
from BOOKS as B 
where B.name = 'GOOD BOOK' 
inner join select * 
from AUTHOR as A 
where A.AUTHOR_NAME = 'GOOD AUTHOR' on B.BOOK_ID = A.BOOK_ID 

select * 
from BOOKS as B 
inner join AUTHOR as A on B.BOOK_ID = A.BOOK_ID 
where B.name = 'GOOD BOOK' 
    and A.AUTHOR_NAME = 'GOOD AUTHOR' 

我不知道这是更快(更好的性能)使用,为什么?

+1

既不是Oracle的有效语法(第二个更接近,但在表别名中失去'as')。不知道MySQL或DB2的第一个是否正确。无论如何,您标记的三个数据库的答案可能不同。你是否使用实际使用的数据库中的真实数据进行过任何性能测试,或者查看执行计划等? –

+0

首先对于db2是无效的,我不会想到mysql – Esperento57

+0

问题是关于基准差异,而不是代码的有效性。从这个例子很明显,作者问如何更好地构建查询性能。 – Alex

回答

0

我拿了你的两个例子,并使用EMP和DEPT在Oracle中重写它们。我相信这些查询代表你正在尝试做的事情;如果不是,请随时纠正我。我还添加@ mathguy的例子(重新编写)

select * 
from EMP E 
inner join (select * 
      from DEPT D 
      where d.loc = 'DALLAS') d1 
on d1.deptno = e.deptno 
where e.job = 'CLERK' 


select * 
from DEPT D 
inner join EMP E 
on D.deptno = E.deptno 
where d.loc = 'DALLAS' 
and e.job = 'CLERK' 

select * 
from (select * from dept where loc = 'DALLAS') D 
inner join 
     (select * from emp where job = 'CLERK') E 
on e.deptno = d.deptno 

我产生了所有的查询执行计划,事实证明,他们都是一样的。 Oracle将执行基于成本的转换 - 基本上重新编写查询以生成最佳执行计划。执行计划如下:

--------------------------------------------------------------------------- 
| Id | Operation   | Name | Rows | Bytes | Cost (%CPU)| Time  | 
--------------------------------------------------------------------------- 
| 0 | SELECT STATEMENT |  |  |  |  4 (100)|   | 
|* 1 | HASH JOIN   |  |  1 | 59 |  4 (0)| 00:00:01 | 
|* 2 | TABLE ACCESS FULL| DEPT |  1 | 20 |  2 (0)| 00:00:01 | 
|* 3 | TABLE ACCESS FULL| EMP |  4 | 156 |  2 (0)| 00:00:01 | 
--------------------------------------------------------------------------- 

Predicate Information (identified by operation id): 
--------------------------------------------------- 

    1 - access("E"."DEPTNO"="D"."DEPTNO") 
    2 - filter("D"."LOC"='DALLAS') 
    3 - filter("E"."JOB"='CLERK') 
0

即使语法错误,您的意图很明确。使用Oracle语法(我相信这是下面两个查询的全部SQL标准),您想知道将WHERE条件单独应用于每个表,然后只进行连接,还是更便宜连接,然后将WHERE条件应用于连接的行。

答案是,在几乎所有情况下,首先应用WHERE条件应该会更便宜 - 特别是如果您有索引和可用于高效访问基表行的索引。这是因为几乎总是访问硬盘上的行的I/O要么是最耗时的,要么是最耗时的操作之一。使用索引,查询引擎可能能够在CPU中发生任何操作之前,从一个表或另一个(或两者)读取少量行。这就是说,只为甲骨文(我所知道的唯一一个)说话,你需要的是两件事:(1)对Google的一些熟悉,和(2)搜索的短语,即“谓词推动” 。在与你一样简单的情况下,即使使用第二种语法,Oracle优化器也会将谓词(WHERE条件)“推送”到每个基表中。如果您为第二个查询运行解释计划,则可以轻松看到这一点。

为了完整,这里是两个查询的正确语法。 (一般来说,你不应该使用*在SELECT子句 - 你应该单独命名列 - 但你没有描述任何实际的表,所以我别无选择。)

select * 
from (select * from books where name = 'Good Book' ) b 
     inner join 
    (select * from authors where name = 'Good Author') a 
     on b.book_id = a.book_id 

(顺便说一句,这是一个奇怪的安排 - 我宁愿期望authors表的主键author_idbooks有一个外键author_id引用authors,并加入将在这些列......但我明白这不是一个实际的设置。 )

select * from books b inner join authors a on b.book_id = a.book_id 
where a.name = 'Good Author' and b.name = 'Good Book'