由于查询计划,简单连接需要太长时间才能运行

时间:2015-01-15 10:50:01

标签: sql-server performance join sql-execution-plan

一些上下文:我有两个表,小表和bigtable。 Smalltable包含10,000行,而bigtable包含2,000,000,我使用的是SQL Server 2008.我从查询开始如下:

select * from [dbo].[smalltable]  t1 
INNER JOIN
[dbo].[bigtable] t2 
on (t1.name1=t2.firstname and t1.name6=t2.lastname) or (t1.name6=t2.firstname and t1.name1=t2.lastname)

这个查询在我杀死它之前运行了超过15分钟 - 在检查查询计划时,它使用嵌套循环来进行内连接。

然后我重写了如下查询:

select * from [dbo].[smalltable]  t1 
INNER JOIN
[dbo].[bigtable] t2 
on (t1.name1=t2.firstname and t1.name6=t2.lastname)
UNION
select * from [dbo].[smalltable]  t1 
INNER JOIN
[dbo].[bigtable] t2 
on (t1.name6=t2.firstname and t1.name1=t2.lastname)

然后使用哈希匹配执行上面的两个查询,整个查询在4秒内运行。

我的问题是,为什么SQL Server得到的查询计划如此错误,无论如何我可以修复原始查询而不重写它?我尝试添加提示以对第一个查询使用哈希匹配,但似乎不允许您使用多个连接条件?

更新:根据请求添加了表中数据类型的示例。请注意,代码正在查找可能已交换名称的名称匹配项:

小表(列名1,名称6)

John, Smith
Johnny, Smith
Smythe, Jon
Michaels, Robert
Bob, Brown

Bigtable(列名字,姓氏)

John, Smith
John, Smythe
Johnny, Smith
Alison, Roberts
Robert, Michaels
Janet, Green

1 个答案:

答案 0 :(得分:2)

这是SQL Server优化程序中的一个问题。

条件(t1.name1=t2.firstname and t1.name6=t2.lastname)仅使用聚簇索引查找,因此非常快,即使使用非常大的表也几乎立即执行。

但条件是OR

(t1.name1=t2.firstname and t1.name6=t2.lastname) or (t1.name6=t2.firstname and t1.name1=t2.lastname)

通常执行全扫描通常会执行更差的操作。您应该看到查询的执行计划。

  

查询优化器将始终执行表扫描或群集   如果查询中的WHERE子句包含OR,则对表进行索引扫描   运算符,如果OR子句中的任何引用列不是   索引(或没有有用的索引)。因此,如果你使用   使用OR子句的许多查询,您将需要确保每个   WHERE子句中的引用列具有索引。

     

如果您有一个使用OR的查询,但它没有得到最佳使用   索引,考虑将其重写为UNION,然后进行测试   性能。只有通过测试才能确定一个版本的   你的查询会比另一个更快。

See here。所以很快你的第一个OR查询就没有充分利用索引。

我相信除了用UNION(正如你所做的)或APPLY重写查询之外别无他法,优化器也不会这样做。