将约束添加到分区视图

时间:2017-08-31 14:12:15

标签: sql sql-server sql-execution-plan partitioned-view

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

例如,假设我有一个订单&通过分区视图访问的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')

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

0 个答案:

没有答案