加入前与加入后选择列

Posted

技术标签:

【中文标题】加入前与加入后选择列【英文标题】:Select columns before join vs after join 【发布时间】:2019-10-09 07:33:20 【问题描述】:

我想知道在我加入两个(或十个......)表之前或之后根据性能选择相关列是否会有所不同。

假设每个表 (A / B) 最初有 20-30 列。

示例 1:

SELECT A.col1, A.col2, B.col3, B.col4
FROM A
LEFT JOIN B ON B.col2 = A.col2

示例2:

SELECT A.col1, A.col2, B.col3, B.col4
FROM (SELECT col1, col2 FROM A) A
LEFT JOIN (SELECT col2, col3, col4 FROM B) B ON (B.col2 = A.col2)

性能有区别吗?

【问题讨论】:

执行计划告诉你什么? 任何 dbms 都应该优化它。执行版本 1 以保持代码简单,跳过那些子查询。 我最终使用了带有 SELECT DISTINCT 的第二个示例 - 不是因为性能本身,而是因为使用 78GB 表,我遇到了磁盘错误。我猜这取决于更快的优化器的能力(?),但对于我的具体情况,事实证明还有存储因素。 好吧,如果您将DISTINCT 应用于其中一个派生表,那将是一个完全不同的查询。 这意味着您的查询返回重复项,这可能意味着您的连接条件不完整(它会产生部分笛卡尔积)。 【参考方案1】:

任何现代优化器都会将这两个查询视为相同。因此,为了便于阅读,请使用第一个。

在线示例:

Postgres

Hash Right Join  (cost=17.20..31.12 rows=320 width=444)
  Hash Cond: (b.col2 = a.col1)
  ->  Seq Scan on b  (cost=0.00..13.10 rows=310 width=226)
  ->  Hash  (cost=13.20..13.20 rows=320 width=222)
        ->  Seq Scan on a  (cost=0.00..13.20 rows=320 width=222)

Oracle

---------------------------------------------------------------------------
| Id  | Operation          | Name | Rows  | Bytes | Cost (%CPU)| Time     |
---------------------------------------------------------------------------
|   0 | SELECT STATEMENT   |      |     5 |   715 |     6   (0)| 00:00:01 |
|*  1 |  HASH JOIN OUTER   |      |     5 |   715 |     6   (0)| 00:00:01 |
|   2 |   TABLE ACCESS FULL| A    |     3 |   195 |     3   (0)| 00:00:01 |
|   3 |   TABLE ACCESS FULL| B    |     5 |   390 |     3   (0)| 00:00:01 |
---------------------------------------------------------------------------

SQL Server - 这两个计划实际上略有不同,但总体方法是相同的

不确定“计算标量”在那里做什么(我对 SQL Server 的经验非常有限),但成本似乎表明它并没有真正改变任何东西。


mysql 也生成完全相同的计划(DbFiddle 不会让我为 MySQL 运行解释)

id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra                                             
---+-------------+-------+------------+------+---------------+-----+---------+-----+------+----------+---------------------------------------------------
 1 | SIMPLE      | A     |            | ALL  |               |     |         |     |    3 |      100 |                                                   
 1 | SIMPLE      | B     |            | ALL  |               |     |         |     |    5 |      100 | Using where; Using join buffer (Block Nested Loop)

【讨论】:

【参考方案2】:

是的,第二个示例会慢一些,因为您编写了一个子查询,因此执行计划会更长,首先是子查询内部的选择比外部选择。 您正在查询它两次。第一个示例是正确的方法。

【讨论】:

这对于任何现代 DBMS 来说都是完全错误的——两者都会准确地生成执行计划

以上是关于加入前与加入后选择列的主要内容,如果未能解决你的问题,请参考以下文章

选择列的最大值时加入表

加入和分组依据 - 选择列表中的列无效

Redshift 加入元数据表并选择列

Hibernate - 加入策略选择了太多列

在选择要加入的列时加入多个 data.frame

excel每个单元格多行内加入相同的内容?