在今天的文章里,我想谈下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. SSO单点登录实现原理与总结

    一.什么是单点登录SSO(Single Sign-On) SSO是一种统一认证和授权机制,指访问同一服务器不同应用中的受保护资源的同一用户,只需要登录一次,即通过一个应用中的安全验证后,再访问其他应用 ...

  2. Verilog学习笔记基本语法篇(十三)...............Gate门

    Verilog中已有一些建立好的逻辑门和开关的模型.在所涉及的模块中,可通过实例引用这些门与开关模型,从而对模块进行结构化的描述. 逻辑门: and (output,input,...) nand ( ...

  3. GJM : Python简单爬虫入门 (一) [转载]

    版权声明:本文原创发表于 [请点击连接前往] ,未经作者同意必须保留此段声明!如有侵权请联系我删帖处理! 为大家介绍一个简单的爬虫工具BeautifulSoup BeautifulSoup拥有强大的解 ...

  4. (转)T-SQL查询处理执行顺序(一)

    对于T-SQL编程,用得最广泛的,莫过于查询(Querying).要想写出高质量.高性能的查询语句,必须深入地了解逻辑查询处理. 一.逻辑查询处理的各个阶段 (5)SELECT DISTINCT TO ...

  5. [Tool] SourceTree初始化GitFlow遇到错误(git command not found)的解决方案

    [Tool] SourceTree初始化GitFlow遇到错误(git command not found)的解决方案 问题情景 使用SourceTree,可以方便开发人员快速的套用GitFlow开发 ...

  6. Select-or-Die:灵活的 jQuery 下拉列表插件

    Select-or-Die 是一个 jQuery 插件,用来自定义下拉列表(Select)元素.原生的下拉选择元素在各个浏览器的默认样式差异很多,而且自定义样式很困难,因此 Web 开发人员喜欢使用插 ...

  7. JavaScript实战(带收放动画效果的导航菜单)

    虽然有很多插件可用,但为了共同提高,我做了一系列JavaScript实战系列的实例,分享给大家,前辈们若有好的建议,请务必指出,免得误人子弟啊! ( 原创文章,转摘请注明:苏福:http://www. ...

  8. PyCharm使用(完全图解(最新经典))

    PyCharm使用 一.PyCharm设置(版本:PyCharm 2016.1.2)  1.python环境设置        1.1.pycharm新建程序自动补全编码和环境: pycharm设置在 ...

  9. hibernate 入门([数据访问中间件] 开源框架)

    1.内容:  hibernate 也是一个经典的[数据访问中间件] 开源框架.    2.hibernate核心组件       SessionFactory[整个数据的操作]重量级组件       ...

  10. ABAP中的Table Control编程

          SAP中,Table Control是在Screen中用的最广泛的控件之一了,可以实现对多行数据的编辑.       简单来说,Table Control是一组屏幕元素在Screen上的重 ...