我们目前有一些客户,他们的查询需要很长时间才能从分区视图中获得结果。经过仔细检查,我们发现了扫描每个表的执行计划,而不仅仅是那些具有相关数据的表。
为了隔离这种行为,我从https://technet.microsoft.com/en-us/library/ms190019(v=sql.105).aspx获取了分区视图示例并重新创建了我们的问题:
在此示例中,我们有 12 个表(针对 1998 年的每个月):
CREATE TABLE Jan1998sales
(
OrderID INT,
CustomerID INT NOT NULL,
OrderDate DATETIME NULL CHECK(DATEPART(yy, OrderDate) = 1998),
OrderMonth INT CHECK (OrderMonth = 1),
DeliveryDate DATETIME NULL CHECK(DATEPART(MM, DeliveryDate) = 1),
CONSTRAINT Jan1998sales_OrderIDMonth PRIMARY KEY (OrderID, OrderMonth)
)
我们正在查看如下视图:
CREATE VIEW Year1998Sales
AS
(
SELECT * FROM Jan1998Sales
UNION ALL
SELECT * FROM Feb1998Sales
UNION ALL
SELECT * FROM Mar1998Sales
UNION ALL
[...]
UNION ALL
SELECT * FROM Dec1998Sales
)
现在我们有了一个运行良好的查询(只扫描必要的表):
SELECT * FROM Year1998Sales
WHERE (OrderMonth = 5 OR OrderMonth = 6) AND CustomerID = 64892
但是如果我们用参数过滤,它会突然扫描所有表:
DECLARE @MonthA int = 5
DECLARE @MonthB int = 6
SELECT * FROM Year1998Sales
WHERE (OrderMonth = @MonthA OR OrderMonth = @MonthB) AND CustomerID = 64892
我解释这种行为的第一个猜测是 Microsoft SQL Server 会构建一个执行计划,它会扫描所有表,并在每次执行此查询时重用它,因此始终扫描所有表。
有谁知道我们如何让 SQL Server 只扫描必要的表并仍然使用参数化过滤器?或者任何人都可以确认这是 SQL Server 执行计划生成器中的错误吗?
有关完整代码,请查看此 SQL Fiddle: http ://sqlfiddle.com/#!6/e1f33/1