【问题标题】:Select from two tables joid vs Joining two Selects从两个表中选择 joid 与加入两个选择
【发布时间】:2017-02-28 16:09:32
【问题描述】:

我总是看到人们使用这两种方式来连接两个或多个表。

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'

我想知道使用哪个更快(性能更好),为什么?

【问题讨论】:

  • 这两种语法都不是 Oracle 的有效语法(第二个更接近,但在表别名中丢失了 as)。不知道第一个是否适用于 MySQL 或 DB2。无论如何,您为此标记的三个数据库的答案可能会有所不同。您是否对实际使用的数据库中的真实数据进行过任何性能测试,或者查看过执行计划等?
  • first 对 db2 无效,我不考虑进入 mysql
  • 问题是关于基准差异,而不是代码的有效性。从示例中可以清楚地看出,作者询问如何更好地构建查询性能。

标签: mysql sql oracle join db2


【解决方案1】:

我采用了您的两个示例,并使用 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')

【讨论】:

    【解决方案2】:

    您的意图很明确,即使语法错误。使用 Oracle 语法(我相信这是下面两个查询的所有 SQL 标准),您想知道将 WHERE 条件分别应用于每个表然后才进行连接是否更有效,或者这样做是否更便宜连接,然后将 WHERE 条件应用于连接的行。

    答案是,在几乎所有情况下,首先应用 WHERE 条件应该更便宜 - 特别是如果您有索引等可用于有效访问基表行的情况。这是因为访问硬盘上的行的 I/O 几乎总是最耗时或最耗时的操作之一。使用索引,查询引擎可能只能在 CPU 中发生任何操作之前从一个表或另一个(或两者)读取少量行。

    话虽如此,仅代表 Oracle(我知道的唯一一个),您需要两件事:(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_id 和 books 有一个外键 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'
    

    【讨论】:

      猜你喜欢
      • 2018-08-07
      • 1970-01-01
      • 1970-01-01
      • 2016-07-02
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-08-02
      相关资源
      最近更新 更多