我设置的分区视图有一个奇怪的问题。
例如,假设我有一个 Orders & 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'
实际执行计划导致仅扫描 Orders 和 OrderTypes:
表“订单类型”。扫描计数 1,逻辑读取 52,物理读取 0,预读读取 0,lob 逻辑读取 0,lob 物理读取 0,lob 预读读取 0。
表“订单”。扫描计数 1,逻辑读取 102,物理读取 0,预读读取 0,lob 逻辑读取 0,lob 物理读取 0,lob 预读读取 0。
但是,当我针对另一个表加入分区视图时,我在执行计划中遇到了一些意外行为。
设置一个小表,其中包含来自 Orders 和 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表,但是执行计划很糟糕。Orders 和 OrderTypes 表都被扫描、连接,然后与临时表连接。(Orders 表有 20,000 条记录;临时表有 20 条)。
针对 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 表,因为约束已被删除。
为什么当另一个表连接到视图时,具有两个约束 ([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')
显然我不能发布两个以上的链接,但我有一个示例脚本,它使用虚拟数据重新创建问题。