加入前与加入后选择列
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 来说都是完全错误的——两者都会准确地生成执行计划以上是关于加入前与加入后选择列的主要内容,如果未能解决你的问题,请参考以下文章