SQL Server视图执行计划:是WHERE还是与UNION相同



我有一个视图,它是联接的集合。为了这个问题的目的,我将把观点简化如下。注意,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通过仅连接表1中第1列中的值为"abc"的记录子集和表2中第2列中值为"xyz"的记录子集来优化上述查询。换言之,SQL Server执行计划在应用联接之前将筛选巧妙地应用于视图中的各个表,从而减少了联接中需要考虑的记录数量。

但是,如果我通过将WHERE子句中的AND运算符更改为OR运算符来更改前一个查询,则执行计划在执行联接之前不会应用筛选。

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

上面查询的执行计划首先连接表1和表2中的所有记录,然后第二个应用where子句。这符合布尔逻辑,因为OR运算符测试不能满足,直到表被连接,并且第1列和第2列中的值都存在并被考虑在内。

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

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使用类似于上次查询的执行计划对其进行优化

谢谢。

WHERE ... OR ...UNION不同。如果单个行在Column1中具有值abc,在Column2中具有值xyz,则在WHERE ... OR ...的情况下它将仅产生一行,而在UNION的情况下产生两行。您可能会争辩说UNION删除了重复项(因为它不是UNION ALL),我认为这是一个简化的示例,省略了正在投影的其他列。但是,即使考虑到这个示例ad literam,我也可以给出另一种情况,其中两个行对于Column1具有值abc,对于Column2具有值xyz,并且在这种情况下,第一个查询返回两行,而第二个查询返回1。QED,您所期望的优化无法实现,因为这是不正确的。

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

它可以执行与您提供的示例类似的转换。你需要计算出雷穆斯回答中提到的细节。我确信这是可行的。例如,您可以使用这样一个事实:您可以将UNION重写为FULL OUTER JOIN。这使您能够插入正确的重复数据消除条件。

截至2012年,这一转变尚未实施。这很不幸,但产品团队无论如何都无法提供一个完美的优化器。我们的产品非常好。

是否有一种方法可以定义视图,以便SQL Server使用类似于上次查询的执行计划对其进行优化?

据我所知并非如此。

我知道这个答案对你来说并没有改善,但情况就是这样。现在,请考虑创建索引视图。通过这种方式,您可以预先生成感兴趣的行的子集。您可以创建跨多个表的列的索引。可以为表达式编制索引。

相关内容

  • 没有找到相关文章

最新更新