Нечетный план выполнения при добавлении ограничения в представление раздела

У меня странная проблема с секционированным представлением, которое я настроил.

Например, ради, скажем, у меня есть таблица 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'

Фактический план выполнения приводит к тому, что сканируются только заказы и типы заказов:

Таблица "Типы заказов". Сканирование 1, логическое чтение 52, физическое чтение 0, чтение с опережением 0, логическое чтение с 0, физическое чтение с 0, чтение с опережением 0.
Таблица "Заказы". Сканирование 1, логическое чтение 102, физическое чтение 0, чтение с опережением 0, логическое чтение с 0, физическое чтение с 0, чтение с опережением 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 & OrderTypes сканируются, объединяются, а затем соединяются с временной таблицей. (Таблица заказов содержит 20000 записей; временная таблица содержит 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')

Очевидно, я не могу опубликовать более двух ссылок, но у меня есть пример сценария, который воссоздает проблему с фиктивными данными.

0 ответов

Другие вопросы по тегам