SQL Server视图执行计划:与UNION在何处或相同?

时间:2012-03-29 04:21:58

标签: sql-server

我有一个视图,它是一个连接集合。出于这个问题的目的,我将简化视图如下。注意,Table1.Table1ID是主键,Table2.Table1ID是外键。

CREATE VIEW [View1] AS
SELECT t1.Column1, t2.Column2
FROM Table1 t1
JOIN Table2 t2 ON t1.Table1ID = t2.Table1ID

为此目的使用视图很好,因为它减少了我在代码中必须执行的连接数,并且它允许SQL Server更有效地优化连接。例如:

SELECT Column1, Column2
FROM View1
WHERE Column1 = 'abc'
AND Column2 = 'xyz'
GROUP BY Column1, Column2

SQL Server通过仅连接Table1中记录的子集来优化上述查询,其中Column1中的值为'abc',而Table2中的记录子集(其中Column2中的值为'xyz')。换句话说,SQL Server执行计划在应用连接之前巧妙地将过滤应用于视图中的各个表,从而减少了在连接中需要考虑的记录数。

但是,如果我通过将AND子句中的WHERE运算符更改为OR运算符来更改以前的查询,则执行计划在执行连接之前应用过滤。

SELECT Column1, Column2
FROM View1
WHERE Column1 = 'abc'
OR Column2 = 'xyz'
GROUP BY Column1, Column2

上述查询的执行计划首先连接Table1和Table2中的所有记录,然后应用where子句第二个。这符合布尔逻辑,因为在表连接并且Column1和Column2中的值都存在并被占用之前,不能满足OR运算符测试。

另一方面,以下查询返回与前一个查询相同的结果集。

SELECT Column1, Column2
FROM View1
WHERE Column1 = 'abc'
UNION
SELECT Column1, Column2
FROM View1
WHERE Column2 = 'xyz'

后两个查询产生相同的结果,但是SQL Server优化了两者中的第二个,以便执行计划在接受连接之前将where子句应用于相应SELECT语句中的相应表在视图中,导致连接的记录更少。即使视图实际被调用两次并且UNION返回结果记录集的交集,这也会导致整体查询更有效。

我的问题是:

  • 为什么SQL Server不使用类似于上一个查询的执行计划来优化倒数第二个查询?
  • 有没有办法定义视图,以便SQL Server使用类似于上一个查询的执行计划对其进行优化?

谢谢。

2 个答案:

答案 0 :(得分:0)

WHERE ... OR ...是与UNION不同的查询。如果单行在abc中的值Column1xyz中的Column2,则WHERE ... OR ...情况下只会生成一行但UNION中只有两行1}}案例。您可能会争辩UNION删除重复项(因为不是UNION ALL),我说这是一个简化的示例,省略了其他正在投影的列。但是,即使考虑这个示例ad-literam,我也可以给出另一种情况,其中两个行的abcColumn1的{​​{1}}值xyz在这种情况下,第一个查询返回两行,而第二个返回1. QED,您期望的优化不会发生因为不正确。

答案 1 :(得分:0)

  

为什么SQL Server不使用类似于上一个查询的执行计划来优化倒数第二个查询?

它可以进行类似于您提供的示例的转换。你需要弄清楚Remus回答中提到的细节。我很确定这是可行的。例如,您可以使用以下事实:您可以将UNION重写为FULL OUTER JOIN。这允许您插入正确的重复数据删除条件。

此转换自2012年起未实施。这很不幸,但产品团队无论如何都无法提供完美的优化器。我们所拥有的是非常好的。

  

有没有办法定义视图,以便SQL Server使用类似于上一个查询的执行计划对其进行优化?

不是我知道的。

我知道这个答案对你没有改善,但情况就是如此。目前,请考虑创建索引视图。这样,您就可以预先生成您感兴趣的行的子集。您可以创建跨多个表的列的索引。您可以索引表达式。