在今天的文章里,我想谈下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. jquery中ajax 从前端到后端 完整过程解析

    几个原则: 1.get方式访问浏览器时,常加参数缘由: GET访问浏览器是等幂的,就是一个相同的URL只有一个结果[相同是指整个URL字符串完全匹配],所以第二次访问的时候如果 URL字符串没变化,浏 ...

  2. 开始自学H5前端-第一天

    自从iOS工作丢了后 就萌生了自学这个想法 但是一直在纠结学哪一门语言好 我是计算机科学与技术专业的 其实对于我来说 学啥都算是有点基础的 但是被iOS坑惨了之后 就会不自觉的进行各个方向和前景分析 ...

  3. JS this,call和apply以及回调函数

    this this引用,引用的是一个对象,对象不同或函数调用方式的不同,this引用会根据代码的上下文语境自动改变引用对象的特性. 引用规则 1,在最外层代码中,this引用引用的是全局对象(wind ...

  4. 【java学习系列】 Android第一本书《第一行代码》

    开始Java的学习,从Android,开始吧.<第一代码>开始阅读和调试demo例子. 下面是 <第一行代码>的思维导图:

  5. Atitit.atiRI  与 远程调用的理论and 设计

    Atitit.atiRI  与 远程调用的理论and 设计 1. 怎么做到透明化远程服务调用?1 2. 2  怎么对消息进行编码和解码1 2.1.  确定消息数据结构dsl1 2.1.1. 消息里为什 ...

  6. 【追寻javascript高手之路05】理解事件流

    前言 新的一天又开始了,我们对今天对未来抱有很大期待,所以开始我们今天的学习吧,在此之前来点题外话,还是爱好问题. 周三的面试虽然失败,但是也是很有启迪的,比如之前我就从来没有想过爱好问题,我发现我的 ...

  7. [deviceone开发]-基础文件管理器

    一.简介 主要实现本地文件管理功能,主要功能为复制.粘贴.剪切目录或者文件. 二.效果 三.相关下载 https://github.com/do-project/code4do/tree/master ...

  8. VS2012 asp.net mvc 4 运行项目提示:"错误消息 401.2。: 未经授权: 服务器配置导致登录失败"

    创建mvc4 应用程序发布,运行出错.出现未经授权: 服务器配置导致登录失败.请验证您是否有权基于您提供的凭,后来找得解决方法: 打开点站的web.confg文件,将: <authorizati ...

  9. form中动态生成Radiobutton控件

    public partial class GetLabelFields : Form { int tableCount; public GetLabelFields(AxMapControl axma ...

  10. 错误解决:SharePoint Designer 2010编辑后,出现数据源控件未能执行插入命令,data source control failed to execute the insert command

    打了SharePoint 2010 最新的SP 2的补丁,但是使用SharePoint Designer 2010 定义任何一个列表的“插入视图”时,总是出现标题那样的错误: 数据源控件未能执行插入命 ...