由于查询计划,简单连接 运行 花费的时间太长
Simple join takes far too long to run due to query plan
一些上下文:我有两个表,smalltable 和 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 服务器得到的查询计划如此错误,我是否可以在不重写的情况下修复原始查询?我尝试添加提示以在第一个查询中使用哈希匹配,但似乎不允许您使用多个连接条件?
更新:根据要求在表格中添加了数据类型的示例。请注意,代码正在查找可能已交换名称的名称匹配项:
Smalltable(列 name1,name6)
John, Smith
Johnny, Smith
Smythe, Jon
Michaels, Robert
Bob, Brown
Bigtable(列名,姓氏)
John, Smith
John, Smythe
Johnny, Smith
Alison, Roberts
Robert, Michaels
Janet, Green
这是 SQL 服务器优化器中的一个问题。
条件 (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)
通常执行全扫描时性能要差得多。您应该看到查询的执行计划。
The Query Optimizer will always perform a table scan or a clustered
index scan on a table if the WHERE clause in the query contains an OR
operator and if any of the referenced columns in the OR clause are not
indexed (or do not have a useful index). Because of this, if you use
many queries with OR clauses, you will want to ensure that each
referenced column in the WHERE clause has an index.
If you have a query that uses ORs and it is not making the best use
of indexes, consider rewriting it as a UNION and then testing
performance. Only through testing can you be sure that one version of
your query will be faster than another.
See here。所以很快你的第一个 OR 查询就没有很好地利用索引。
我相信除了用 UNION 重写查询(就像你所做的那样)或 APPLY,我相信没有其他方法,优化器不会这样做。
一些上下文:我有两个表,smalltable 和 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 服务器得到的查询计划如此错误,我是否可以在不重写的情况下修复原始查询?我尝试添加提示以在第一个查询中使用哈希匹配,但似乎不允许您使用多个连接条件?
更新:根据要求在表格中添加了数据类型的示例。请注意,代码正在查找可能已交换名称的名称匹配项:
Smalltable(列 name1,name6)
John, Smith
Johnny, Smith
Smythe, Jon
Michaels, Robert
Bob, Brown
Bigtable(列名,姓氏)
John, Smith
John, Smythe
Johnny, Smith
Alison, Roberts
Robert, Michaels
Janet, Green
这是 SQL 服务器优化器中的一个问题。
条件 (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)
通常执行全扫描时性能要差得多。您应该看到查询的执行计划。
The Query Optimizer will always perform a table scan or a clustered index scan on a table if the WHERE clause in the query contains an OR operator and if any of the referenced columns in the OR clause are not indexed (or do not have a useful index). Because of this, if you use many queries with OR clauses, you will want to ensure that each referenced column in the WHERE clause has an index.
If you have a query that uses ORs and it is not making the best use of indexes, consider rewriting it as a UNION and then testing performance. Only through testing can you be sure that one version of your query will be faster than another.
See here。所以很快你的第一个 OR 查询就没有很好地利用索引。
我相信除了用 UNION 重写查询(就像你所做的那样)或 APPLY,我相信没有其他方法,优化器不会这样做。