我有一个视图,它是一个连接集合。出于这个问题的目的,我将简化视图如下。注意,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
返回结果记录集的交集,这也会导致整体查询更有效。
我的问题是:
谢谢。
答案 0 :(得分:0)
WHERE ... OR ...
是与UNION
不同的查询。如果单行在abc
中的值Column1
和xyz
中的Column2
,则WHERE ... OR ...
情况下只会生成一行但UNION
中只有两行1}}案例。您可能会争辩UNION
删除重复项(因为不是UNION ALL
),我说这是一个简化的示例,省略了其他正在投影的列。但是,即使考虑这个示例ad-literam,我也可以给出另一种情况,其中两个行的abc
和Column1
的{{1}}值xyz
在这种情况下,第一个查询返回两行,而第二个返回1. QED,您期望的优化不会发生因为不正确。
答案 1 :(得分:0)
为什么SQL Server不使用类似于上一个查询的执行计划来优化倒数第二个查询?
它可以进行类似于您提供的示例的转换。你需要弄清楚Remus回答中提到的细节。我很确定这是可行的。例如,您可以使用以下事实:您可以将UNION
重写为FULL OUTER JOIN
。这允许您插入正确的重复数据删除条件。
此转换自2012年起未实施。这很不幸,但产品团队无论如何都无法提供完美的优化器。我们所拥有的是非常好的。
有没有办法定义视图,以便SQL Server使用类似于上一个查询的执行计划对其进行优化?
不是我知道的。
我知道这个答案对你没有改善,但情况就是如此。目前,请考虑创建索引视图。这样,您就可以预先生成您感兴趣的行的子集。您可以创建跨多个表的列的索引。您可以索引表达式。