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

2015-01-24 01:41:49 · 作者: · 浏览: 16

在Microsoft SQLServer Management Studio中执行查询时,如果选定工具栏中的按钮,可以看到为查询生成的执行计划。执行计划以图形方式显示了SQL Server查询优化器选择的数据检索方法,如表扫描、排序、哈希匹配等。对于联接查询,SQL Server会根据联接表之间的数据、索引等情况,选择使用嵌套循环联接、合并联接或哈希联接。

7.7.1 嵌套循环联接

嵌套循环联接也称为“嵌套迭代”,它将一个联接输入用作外部输入表(显示为图形执行计划中的顶端输入),将另一个联接输入用作内部(底端)输入表。外部循环逐行处理外部输入表。内部循环会针对每个外部行执行,在内部输入表中搜索匹配行。简单地讲,就是扫描其中的一个联接表,并为该表中的每一行在另一个联接表中搜索匹配行。

如果外部输入较小(不到10行)而内部输入较大且预先创建了索引,则嵌套循环联接尤其有效。在许多小事务中(如那些只影响较小的一组行的事务),索引嵌套循环联接优于合并联接和哈希联接。但在大型查询中,嵌套循环联接通常不是最佳选择。

例如,下面的查询由于Sales.Customer表行数只有1行,而Sales.SalesOrderHeader数据量较大,因此将使用嵌套循环联接,生成的执行计划如图7-11所示。

USE AdventureWorks2014;

GO

SELECT *

FROM Sales.Customer

INNER JOINSales.SalesOrderHeader

ONCustomer.CustomerID = SalesOrderHeader.CustomerID

WHERE Customer.CustomerID = 1;

vce1xFNhbGVzLkN1c3RvbWVyse2xu9f3zqrN4rK/yuTI66Os1Nq+27yvy/fS/dbQsunV0r/Nu6eho7bU09rDv7j2v827p6Osx7bM19Gtu7fUy8vjvau21FNhbGVzT3JkZXJIZWFkZXIuQ3VzdG9tZXJJRCDB0MnPtcRJWF9TYWxlc09yZGVySGVhZGVyX0N1c3RvbWVySUTL99L91rTQ0NK7tM6y6dXSo6zIu7rz1Nm4+tK7uPa8/LLp1dLAtLaozrvSqrfDzsq1xMr9vt3Q0KGjPC9wPjxoMz43LjcuMiC6z7Kiwaq90zwvaDM+PHA+us+yosGqvdPSqsfzwb249srkyOu2vNTaus+yosHQyc/FxdDyo6y6z7KiwdDTycGqvdPOvbTKtcS1yNCno6hPTqOp19O+5Lao0uWho9PJ09rDv7j2yuTI67a80tHFxdDyo6zS8rTLus+yosGqvdO9q7TTw7+49srkyOu78cih0rvQ0LKivavG5L340NCxyL3PoaPA/cjno6y21NPaxNrBqr3TstnX96OsyOe5+9DQz+C1yNTyt7W72KGjyOe5+9DQsrvP4LXIo6zU8rfPxvrWtb3P0KG1xNDQsqK007jDyuTI67vxtcPB7dK70NCho9Xi0ru5/bPMvavW2Li0vfjQ0KOs1rG1vbSmwO3N6sv509C1xNDQzqrWuaGjPC9wPjxwPrrPsqLBqr3TstnX97/J0tTKx7Ojueay2df3o6zSsr/J0tTKx7bgttS24LLZ1/eho7bgttS24LrPsqLBqr3TyrnTw8HZyrGx7bTmtKLQ0KGjyOe5+8O/uPbK5Mjr1tDT0NbYuLTWtaOs1PLU2rSmwO3G5NbQ0ru49srkyOvW0LXEw7+49tbYuLTP7sqxo6zB7dK7uPbK5MjrsdjQ69bYyMa1vdbYuLTP7rXEv6rKvM671sOhozwvcD48cD66z7Kiwaq907G+ye21xMvZtsi63L/so6y1q8rHyOe5+7rPsqLB0MnPzrS9qMGiy/fS/aOs0aHU8brPsqLBqr3T09C/ycTcu+G3x7Ojt9HKsaOs0vLOqsv8ytfPyNKqttTB0L340NDFxdDystnX96GjyLu2+KOsyOe5+8r9vt3Bv7rctPPH0sTcubu008v30v3W0LvxtcPUpMXF0PK1xMv50OjK/b7do6zU8rrPsqLBqr3Tzaizo8rH1+6/7LXEv8nTw8GqvdPL47eooaM8L3A+PHA+wP3I56Osz8LD5rXEsunRr9PvvuS9q7vxyKG2qbWltcTP6s+40MXPoqOs08nT2lNhbGVzT3JkZXJIZWFkZXK6zVNhbGVzT3JkZXJEZXRhaWzU2rrPsqLB0FNhbGVzT3JkZXJJRMnPtry+39PQvtu8r8v30v2jrNLRvq29q8HQvfjQ0MHLxcXQ8qOsy/nS1LLp0a/Txbuvxve74dGh1PG6z7Kiwaq906GjyOfNvDctMTLL+cq+oaM8L3A+PHA+VVNFIEFkdmVudHVyZVdvcmtzMjAxNDs8L3A+PHA+R088L3A+PHA+U0VMRUNUICo8L3A+PHA+RlJPTSBTYWxlcy5TYWxlc09yZGVySGVhZGVyICAgPC9wPjxwPiAgSU5ORVIgSk9JTlNhbGVzLlNhbGVzT3JkZXJEZXRhaWwgIDwvcD48cD4gICAgT05TYWxlc09yZGVySGVhZGVyLlNhbGVzT3JkZXJJRCA9IFNhbGVzT3JkZXJEZXRhaWwuU2FsZXNPcmRlcklEOzwvcD48cD48aW1nIHNyYz0="https://www.cppentry.com/upload_files/article/57/1_lurtx__.jpg" alt="\" />

图7-12 使用合并联接的执行计划

7.7.3 哈希联接

哈希联接可以有效处理未排序的大型非索引输入。因此,它对处理复杂查询的中间结果很有用。查询的中间结果是未经索引的,而且通常不会为查询计划中的下一个操作进行适当的排序。并且,查询优化器只估计中间结果的大小。而对于复杂查询,估计可能有很大的误差,因此如果中间结果比预期的大得多,则处理中间结果的算法不仅必须有效而且必须适度弱化。再像合并联接那样严格要求具备排序列,对于中间结果而言是不现实的,排序成本的付出可能要远远大于数据的直接检索成本。

选择哈希联接的两种情况:一是没有为联接创建合适的索引,二是中间结果比较大。

哈希联接有两种输入:生成输入和探测输入。查询优化器会选择二者中较小的那个作为生成输入,对联接列值应用哈希函数,将生成输入中的行分配到哈希桶中。哈希桶是一种存放所访问数据位置的结构,有了它,进行数据检索时,可以避免不必要的表扫描。

为了验证无索引情况下的哈希联接使用,首先使用下面的语句创建Sales.Customer和S