1

我设置的分区视图有一个奇怪的问题。

例如,假设我有一个 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 的执行计划

为什么当另一个表连接到视图时,具有两个约束 ([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')

显然我不能发布两个以上的链接,但我有一个示例脚本,它使用虚拟数据重新创建问题。

4

0 回答 0