锋利的SQL2014:联接算法(二)

2015-01-24 01:41:49 · 作者: · 浏览: 11
ales.SalesOrderHeader表的副本。

USE AdventureWorks2014;

GO

SELECT TOP 10 *

INTO MyCustomer

FROM Sales.Customer

ORDER BY CustomerID;

SELECT TOP 100 *

INTO MySalesOrderHeader

FROM Sales.SalesOrderHeader

ORDER BY CustomerID;

执行下面的查询,可以看到如图7-13所示的执行计划。

SELECT *

FROM MyCustomer

INNER JOINMySalesOrderHeader

ONMyCustomer.CustomerID = MySalesOrderHeader.CustomerID;

\

图7-13 使用哈希联接的执行计划

下面再来看一个比较有趣的示例。下面的查询语句中仅选择了Sales.Customer中CustomerID = 1的行与Sales.SalesOrderHeader进行联接,由于联接行数很小,所产生中间结果的数据量也比较小,因此,可以看到查询优化器为语句使用了嵌套循环联接。如图7-14所示。

USE AdventureWorks2014;

GO

SELECT *

FROM Sales.Customer

INNER JOINSales.SalesOrderHeader

ONCustomer.CustomerID = SalesOrderHeader.CustomerID

WHERE Customer.CustomerID = 1;

\

图7-14 数据量较小时使用嵌套循环联接

同样是上面的联接,去除掉WHERE筛选条件后数据量明显增大,执行该语句会发现查询优化器使用了哈希联接方式。如图7-15所示。

SELECT *

FROM Sales.Customer

INNER JOINSales.SalesOrderHeader

ONCustomer.CustomerID = SalesOrderHeader.CustomerID;

\

图7-15 数据量较大时使用哈希联接

7.7.4 使用联接提示强制联接策略

联接提示用于指定查询优化器在两个表之间强制执行联接策略,提示符包括LOOP JOIN、MERGE JOIN和HASH JOIN,分别用于嵌套循环、哈希和合并联接。如果指定了多个联接提示,则优化器从允许的联接策略中选择开销最少的联接策略。此外,也可以使用OPTION子句指定联接策略。但是这种方式会影响查询中的所有联接,通常用于旧式联接语法。

1.为每个联接指定单独的联接策略

可以在FROM子句中使用LOOP JOIN、MERGE JOIN和HASH JOIN提示符为每个联接单独指定联接策略。例如,下面的查询语句指定使用嵌套循环联接。

USE AdventureWorks2014;

GO

SELECT *

FROM Sales.Customer

INNER LOOPJOIN Sales.SalesOrderHeader

ONCustomer.CustomerID = SalesOrderHeader.CustomerID;

又如,下面的查询语句指定使用合并联接。

USE AdventureWorks2014;

GO

SELECT *

FROM Sales.Customer

INNERMERGE JOIN Sales.SalesOrderHeader

ONCustomer.CustomerID = SalesOrderHeader.CustomerID;

在多表联接中使用联接提示时,会影响联接的执行顺序。在前面介绍了,在不影响返回结果正确的情况下,查询优化器会按照效率优先的原则,选择首先执行的联接。例如,下面语句的执行计划如图7-16所示,可以看到首先执行的是Sales.SalesOrderHeader与Sales.SalesOrderDetail的联接,然后将联接结果再与Sales.Customer进行联接。

USE AdventureWorks2014;

GO

SELECT *

FROM Sales.Customer

INNER JOINSales.SalesOrderHeader

ONCustomer.CustomerID = SalesOrderHeader.CustomerID

INNER JOINSales.SalesOrderDetail

ON SalesOrderHeader.SalesOrderID =SalesOrderDetail.SalesOrderID;

\

图7-16 未使用联接提示的执行计划

下面的语句为Sales.Customer和Sales.SalesOrderHeader指定了合并联接提示,并且这个提示仅对这两个表起作用,与Sales.SalesOrderDetail的联接策略仍旧由查询优化器决定。由于明确指定了Sales.Customer与Sales.SalesOrderHeader使用合并联接,优化器会先执行该联接,而不是先执行Sales.SalesOrderHeader与Sales.SalesOrderDetail的联接。否则,就会造成Sales.Customer与Sales.SalesOrderHeader和Sales.SalesOrderDetail的联接结果再执行合并联接。图7-17是该语句的执行计划。

SELECT *

FROM Sales.Customer

INNERMERGE JOIN Sales.SalesOrderHeader

ONCustomer.CustomerID = SalesOrderHeader.CustomerID

INNER JOINSales.SalesOrderDetail

ONSalesOrderHeader.SalesOrderID = SalesOrderDetail.SalesOrderID;

\

图7-17 使用联接提示后的执行计划

如果希望Sales.Customer与Sales.SalesOrderHeader和Sales.SalesOrderDetail的联接结果执行合并联接,则应当使用嵌套联接的方式实现,参考下面的语句:

SELECT *

FROM Sales.Customer

INNERMERGE JOIN (Sales.SalesOrderHeader

INNER JOIN Sales.SalesOrderDetail

ONSalesOrderHeader.SalesOrderID = SalesOrderDetail.SalesOrderID)

ONCustomer.CustomerID = SalesOrderHeader.CustomerID;

2.为全部联接指定统一的联接策略

当使用旧式联接语法时,应当使用OPTION子句指定联接策略,但是,这种策略会影响语句中的全部联接,无法为每个联接单独指定不同的联接策略,如:

SELECT *

FROM Sales.Customer, Sales.SalesOrderHeader,Sales.SalesOrderDetail

WHERE Customer.CustomerID =SalesOrderHeader.CustomerID

AND SalesOrderHeader.SalesOrderID= SalesO