我设置的分区视图有一个奇怪的问题。
例如,假设我有一个订单&通过分区视图访问的Orders_Archive表。每个订单都有一个OrderType,可以通过外键访问并存储在外观表中。
订单有一个字段来表示它是活动的还是存档的:
[ArchiveYearMonth] char(5)
。
(我意识到在字符串中存储日期不是最佳的,但为了示例而忽略了这一点。)
这三个表的架构如下所示:
CREATE TABLE Orders
(
Order_ID uniqueidentifier DEFAULT NEWSEQUENTIALID(),
OrderType_ID int NOT NULL,
ArchiveYearMonth AS ('9999/12') PERSISTED,
CONSTRAINT [PK_Orders] PRIMARY KEY CLUSTERED (Order_ID )
)
CREATE TABLE Orders_Archive
(
Order_ID uniqueidentifier DEFAULT NEWSEQUENTIALID(),
OrderType_ID int NOT NULL,
CompletedOn datetime2(3) NOT NULL,
ArchiveYearMonth AS (dbo.[ConvertToYearMonth](CompletedOn)) PERSISTED,
CONSTRAINT [PK_Orders_Archive] PRIMARY KEY CLUSTERED (Order_ID )
)
CREATE TABLE OrderTypes
(
OrderType_ID int IDENTITY(1,1),
OrderType varchar(100),
CONSTRAINT [PK_OrderTypes] PRIMARY KEY CLUSTERED (OrderType_ID )
)
GO
我已经设置了这样的视图:
CREATE VIEW AllOrders_ProperFilter
AS
SELECT Order_ID, OrderType, ArchiveYearMonth
FROM Orders o INNER JOIN OrderTypes oT on o.OrderType_ID = oT.OrderType_ID
WHERE ArchiveYearMonth = '9999/12'
UNION ALL
SELECT Order_ID, OrderType, ArchiveYearMonth
FROM Orders_Archive o INNER JOIN OrderTypes oT on o.OrderType_ID = oT.OrderType_ID
WHERE ArchiveYearMonth <>'9999/12'
GO
直接查询时,其工作正常:
SELECT * FROM AllOrders_ProperFilter WHERE ArchiveYearMonth = '9999/12'
实际执行计划仅产生订单和正在扫描的OrderTypes:
表'OrderTypes'。扫描计数1,逻辑读取52,物理读取0, 预读读取0,lob逻辑读取0,lob物理读取0,lob 预读读数为0.
表'订单'。扫描计数1,逻辑读取102, 物理读取0,预读读取0,lob逻辑读取0,lob 物理读取0,lob预读读取0。
但是,当我将分区视图加入另一个表时,我在执行计划中会遇到一些意外行为。
设置一个小表,其中包含来自订单和订单的一些记录。 Order_Archive表:
SELECT * INTO #tempTbl
FROM
(
SELECT TOP (10) Order_ID
FROM Orders
UNION ALL
SELECT TOP (10) Order_ID
FROM Orders_Archive
) z
现在加入临时表的原始视图:
SELECT *
FROM AllOrders_ProperFilter pView
WHERE Order_ID IN (SELECT Order_ID FROM #tempTbl) AND ArchiveYearMonth = '9999/12'
option (recompile)
结果没问题,只查询Orders表,但执行计划很糟糕。订单和订单OrderTypes表将被扫描,连接,然后连接到临时表。 (订单表有20,000条记录;临时表有20条)。
Execution plan against AllOrders_ProperFilter
现在,如果我从视图中删除分区,并对其进行查询,我会得到不同的结果:
CREATE VIEW AllOrders
AS
SELECT Order_ID, OrderType, ArchiveYearMonth
FROM Orders o INNER JOIN OrderTypes oT on o.OrderType_ID = oT.OrderType_ID
WHERE ArchiveYearMonth = '9999/12'
UNION ALL
SELECT Order_ID, OrderType, ArchiveYearMonth
FROM Orders_Archive o INNER JOIN OrderTypes oT on o.OrderType_ID = oT.OrderType_ID
-- WHERE ArchiveYearMonth <>'9999/12'
GO
执行计划现在扫描临时表,使用PK来搜索Orders表,然后加入OrderTypes。期望它还会查询Orders_Archive表,因为约束已被删除。
Execution plan against AllOrders
为什么具有这两个约束的视图([AllOrders_ProperFilter])在另一个表加入时会表现得如此糟糕?
注意 - 当我对表添加实际约束时,我得到相同的结果:
ALTER TABLE Orders ADD CONSTRAINT
CK_NOTARCHIVED CHECK (ArchiveYearMonth = '9999/12')
ALTER TABLE Orders_Archive ADD CONSTRAINT
CK_ARCHIVED CHECK (ArchiveYearMonth <> '9999/12')
显然我不能发布两个以上的链接,但我有一个示例脚本,可以用虚拟数据重新创建问题。