在今天的文章里,我想谈下SQL Server里一个非常有趣的话题:在表联接里,把表指定顺序的话是否有意义?每次我进行查询和性能调优的展示时,大家都会问我他们是否应该把联接中的表指定下顺序,是否会帮助查询优化器得出一个更好性能的执行计划。我们来看下这个重要又有趣的问题。

合并联接(Inner Joins)

假设在AdventureWorks数据库里,你要在Sales.SalesOrderHeader表和Sales.SalesOrderDetail表之间做一个内联接:

 USE AdventureWorks
GO -- Returns for each SalesOrderHeader record all associated SalesOrderDetail records
-- SQL Server performs a Merge Join, because both tables are phyiscally sorted
-- by the column "SalesOrderID".
SELECT
h.SalesOrderID,
h.CustomerID,
d.SalesOrderDetailID,
d.ProductID,
d.LineTotal
FROM Sales.SalesOrderHeader h
JOIN Sales.SalesOrderDetail d
ON h.SalesOrderID = d.SalesOrderID
ORDER BY SalesOrderID
GO

当我们查看结果的执行计划时,我们可以看到查询优化器选择了合并联接(Inner Join)作为物理联接运算符,Sales.SalesOrderHeader表作为合并联接的外联接。在执行计划里表的顺序和我们在逻辑T-SQL查询里的顺序是一样的。

现在的问题是,当我们在逻辑T-SQL查询里交换下2个表的顺序,执行计划会发生什么?我们来试下:

 -- The logical ordering of the tables during an Inner Join
-- doesn't matter. It's up to the Query Optimnizer to arrange
-- the tables in the best order.
-- This query produces the same execution plan as the previous one.
SELECT
h.SalesOrderID,
h.CustomerID,
d.SalesOrderDetailID,
d.ProductID,
d.LineTotal
FROM Sales.SalesOrderDetail d
JOIN Sales.SalesOrderHeader h
ON d.SalesOrderID = h.SalesOrderID
ORDER BY SalesOrderID
GO

但我们现在看结果的执行计划,我们发现很有意思:

在执行计划里没有任何改变!查询优化器选择了和刚才查询一样的物理执行计划。但为什么?答案非常简单:查询优化器总引用最小的表(基于我们的统计信息!)作为每个物理连接运算符(嵌套循环联接,合并联接,哈希匹配联接)的外联接表。因此在T-SQL查询里的表的逻辑顺序不会对查询优化器造成任何影响。按正确的顺序访问我们的表是查询优化器的职责。

在表A和表B之间的合并联接与表B和表A之间的合并联接是一样的。

外联接(Outer Join)

在外联接(left join,right join)里,表顺序会有啥影响?我们来看下面的查询,在Sales.Customer表和 Sales.SalesOrderHeader表之间进行左联接。

 -- Execute the query with an Outer Join.
-- Now we are also getting back customers that haven't placed orders.
-- The left table is the preserving one, and missing rows from the right table are added with NULL values.
-- SQL Server performs a "Merge Join (Left Outer Join)" in the execution plan.
SELECT
c.CustomerID,
h.SalesOrderID
FROM Sales.Customer c
LEFT JOIN Sales.SalesOrderHeader h
ON c.CustomerID = h.CustomerID
GO

当我们查看结果执行计划时,我们会看到查询优化器已经隐藏了我们的表顺序。

当然这次我们不能修改T-SQL语句里的表顺序,不然查询会返回错误的结果。但当我们在查询里切换下表会发生什么,不是左联接,我们用右联接。我们来试下:

 -- You can rewrite the query from above with a Right Outer Join when you swap the order
-- of the tables. This time you get back the same result (32166 rows).
SELECT
c.CustomerID,
h.SalesOrderID
FROM Sales.SalesOrderHeader h
RIGHT JOIN Sales.Customer c
ON c.CustomerID = h.CustomerID
GO

当我们看执行计划时,我们再次看到没有任何改变:查询优化器转化右联接为左联接,重排了下表还是返回正确的结果。查询优化器的目标是使用最小表作为物理联接运算符的外表。因此在外联接里表的顺序也不会影响查询优化器。只要我们的统计信息是正确的,查询优化器总会选择正确的顺序。

在表A和表B之间的左联接与表B和表A之间的右联接是一样的。

小结:

在这篇文章里我们讨论对于联接,表的顺序是否会影响执行计划。如我们所见,这完全由查询优化器来决定选择优化的表顺序——基于统计信息。在合并联接里表顺序完全不影响,使用外联接的话,SQL Server可以通过切换左联接/右联接来重排表,还是获得正确的结果。

参考文章:

http://www.sqlpassion.at/archive/2015/12/15/table-ordering-for-joins/

Join的表顺序的更多相关文章

  1. JOIN关联表中ON,WHERE后面跟条件的区别

    select * from td  left join (select case_id as sup_case_id , count(*) supervise_number from  td_kcdc ...

  2. join多表连接和group by分组

    join多表连接和group by分组 上一篇里面我们实现了单表查询和top N查询,这一篇我们来讲述如何实现多表连接和group by分组. 一.多表连接 多表连接的时间是数据库一个非常耗时的操作, ...

  3. 【Spark调优】大表join大表,少数key导致数据倾斜解决方案

    [使用场景] 两个RDD进行join的时候,如果数据量都比较大,那么此时可以sample看下两个RDD中的key分布情况.如果出现数据倾斜,是因为其中某一个RDD中的少数几个key的数据量过大,而另一 ...

  4. MySQL JOIN 多表连接

    除了常用的两个表连接之外,SQL(MySQL) JOIN 语法还支持多表连接.多表连接基本语法如下: 1 ... FROM table1 INNER|LEFT|RIGHT JOIN table2 ON ...

  5. 对于大量left join 的表查询,可以在关键的 连接节点字段上创建索引。

    对于大量left join 的表查询,可以在关键的 连接节点字段上创建索引. 问题: 大量的left join 怎么优化 select a.id,a.num,b.num,b.pcs,c.num, c. ...

  6. left join 连表时,on后多条件无效问题

    http://www.cnblogs.com/guixiaoming/p/6516261.html left join 连表时,on后多条件无效问题 最近开发素材库项目,各种关系复杂的表,一度6张表的 ...

  7. 【Spark调优】小表join大表数据倾斜解决方案

    [使用场景] 对RDD使用join类操作,或者是在Spark SQL中使用join语句时,而且join操作中的一个RDD或表的数据量比较小(例如几百MB或者1~2GB),比较适用此方案. [解决方案] ...

  8. mybatis逆向工程,实现join多表查询,避免多表相同字段名的陷阱

    ​ mybatis逆向工程,实现join多表查询,避免多表相同字段名的陷阱 ​ 前言:使用 mybatis generator 生成表格对应的pojo.dao.mapper,以及对应的example的 ...

  9. 大数据开发实战:Hive优化实战3-大表join大表优化

    5.大表join大表优化 如果Hive优化实战2中mapjoin中小表dim_seller很大呢?比如超过了1GB大小?这种就是大表join大表的问题.首先引入一个具体的问题场景,然后基于此介绍各自优 ...

随机推荐

  1. pageEncoding的默认设置

    windows-->preference-->myeclipse-->files and editors-->jsp 右侧 Encoding 选择  ISO 10646/Uni ...

  2. 泛函编程(33)-泛函IO:Free Functor - Coyoneda

    在前几期讨论中我们终于推导出了Free Monad.这是一个Monad工厂,它可以把任何F[A]变成Monad.可惜的是它对F[A]是有所要求的:F必须是个Functor.Free Monad由此被称 ...

  3. CI框架源码阅读笔记9 CI的自动加载机制autoload

    本篇并不是对某一组件的详细源码分析,而只是简单的跟踪了下CI的autoload的基本流程.因此,可以看做是Loader组件的分析前篇. CI框架中,允许你配置autoload数组,这样,在你的应用程序 ...

  4. easyui datagrid 点击表头的事件

    在用datagrid的时候我们可能要用到点击表头来触发一个function,这里有个简单的例子. 首先你得有个能用的datagrid. <div>    <table id=&quo ...

  5. spring mvc WebArgumentResolver不生效

    WebArgumentResolver: SPI for resolving custom arguments for a specific handler method parameter. Typ ...

  6. AngularJs学习第一课 Hello World

    首先先介绍一下:AngularJS是干什么的. AngularJS是为了克服HTML在构建应用上的不足而设计的.HTML是一门很好的为静态文本展示设计的声明式语言,但要构建WEB应用的话它就显得乏力了 ...

  7. 设计3D标签

    java自带的Label太枯燥了,真是拿不出手啊. 所以,我们要设计3D标签!! 看看下面这张图 原理 看看这图,可以看到哈哈有三种颜色:白色.黑色和灰色 实现的时候并不像PS那样,按几个按钮就O了 ...

  8. Dynamics.js - 创建逼真的物理动画的 JS 库

    Dynamics.js 是一个用来创建物理动画 JavaScript 库.你只需要把dynamics.js引入你的页面,然后就可以激活任何 DOM 元素的 CSS 属性动画,也可以用户 SVG 属性. ...

  9. SweetAlert – 替代 Alert 的漂亮的提示效果

    Sweet Alert 是一个替代传统的 JavaScript Alert 的漂亮提示效果.SweetAlert 自动居中对齐在页面中央,不管您使用的是台式电脑,手机或平板电脑看起来效果都很棒.另外提 ...

  10. 【CSS3】CSS3:border-image的详解和实例

    border-image简介 border-image是CSS3中的新特性.目前几乎所有的主流浏览器都已经支持该特性,详情请移步border-image的兼容性. border-image属性及使用说 ...