TransWikia.com

Правильный план для Cross DB views

Stack Overflow на русском Asked by Nick Proskuryakov on December 1, 2020

На уровне представления собираю данные из нескольких БД с одинаковой структурой:

CREATE VIEW [dbo].[TestCrossView] 
AS
(
SELECT
      ID,
      Result.SText,
      Result.DbName
FROM  ( SELECT
              CAST(0 AS INT) AS ID,
              CAST('' AS NVARCHAR (100)) AS [SText],
              CAST('' AS sysname) AS [DbName]
        UNION 
        SELECT
              [id],
              [SText],
              [DbName] AS [DbName]
        FROM  [DbTestCheckCross1]..TableSession
        UNION 
        SELECT
              [id],
              [SText],
              [DbName] AS [DbName]
        FROM   [DbTestCheckCross2]..TableSession
        UNION 
        SELECT
              [id],
              [SText],
              [DbName] AS [DbName]
        FROM   [DbTestCheckCross3]..TableSession ) AS Result
);

Далее выполняю запрос с фильтрацией по имени БД:

DECLARE @DbName sysname = N'DbTestCheckCross1'

SELECT TOP (1000) tcv.[ID]
      ,tcv.[SText]
      ,tcv.[DbName]
  FROM [DbTestCheckCrossMain].[dbo].[TestCrossView] tcv
  WHERE DbName = @DbName

В плане запроса вижу сканы по всем базам внутри представления.

введите сюда описание изображения

Если такой запрос выполняется долго, то запрос которому требуется блокировка схемы, будет ожидать выполнения этого запроса.

Проблему решает хинт OPTION (RECOMPILE) или указание константы в фильтре.

введите сюда описание изображения

Есть ли другой способ заставить движок отсечь ненужные БД?
Секционирование не предлагать 😉

One Answer

Операторы сканирования в плане запроса располагаются за фильтрами, в свойствах которых определены startup expression, например:

Startup_Expression_Predicate

Это означает, что в run-time сканирование будет выполняться только если соответствующий фильтр его пропустит (startup-предикат будет иметь значение True).

Из четырёх веток, объединяемых в Concatenation, фактически лишь одна (выделенная) поставляет данные при указанном значении переменной

Plan_highlighted

Только у выделенного Table Scan число выполнений ненулевое

Number_of_Executions_1

у остальных операторов сканирования оно равно нулю

Number_of_Executions_0

Есть, однако, нюанс. Перед началом выполнения запроса execution engine установит Sch-S блокировки (schema stability) на все таблицы, участвующие в запросе (независимо от того, будет ли происходить чтение данных из конкретной таблицы, или не будет). Соответственно ALTER, TRUNCATE и всё, для чего требуется Sch-M блокировка (schema modification), становятся невозможны на таблицах до окончания запроса.

Если нужно этого по-возможности избегать, то вариант с константой, в данном случае, видимо самый лучший (либо то же самое с помощью динамического запроса). Вариант с RECOMPILE менее желателен, но он может быть не таким уж и злом, если компиляция запроса малозатратна относительно выполнения.

Следует отметить, что Sch-S блокировки устанавливаются также и на время компиляции. С константой или RECOMPILE, когда ненужная таблица полностью выпадает из плана, время нежелательной блокировки будет естественно меньше.

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

Correct answer by i-one on December 1, 2020

Add your own answers!

Ask a Question

Get help from others!

© 2024 TransWikia.com. All rights reserved. Sites we Love: PCI Database, UKBizDB, Menu Kuliner, Sharing RPP