Почему SQL Server «вычисляет скаляр», когда я выбираю постоянный вычисляемый столбец?


21

Три SELECTутверждения в этом коде

USE [tempdb];
GO

SET NOCOUNT ON;

CREATE TABLE dbo.persist_test (
      id            INT NOT NULL
    , id5           AS (id * 5)
    , id5p          AS (id * 5) PERSISTED
);

INSERT INTO dbo.persist_test (id)
VALUES (1), (2), (3);

SELECT id
FROM dbo.persist_test;

SELECT id5
FROM dbo.persist_test;

SELECT id5p
FROM dbo.persist_test;

DROP TABLE dbo.persist_test;

создать этот план:

план выполнения

Почему final SELECT, который выбирает постоянное значение, генерирует оператор Compute Scalar ?


3
Смотрите ответ @ SqlKiwi здесь: Почему План выполнения включает в себя определенный пользователем вызов функции для вычисляемого столбца, который сохраняется? , В вашем запросе только выходной список столбцов из таблицы, [tempdb].[dbo].[persist_test].idи он вычисляет значение, несмотря на то, что он сохранен.
Мартин Смит

Ответы:


14

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

В плане запроса

SELECT id5p
FROM dbo.persist_test;

При сканировании таблицы persist_testгенерируется только idстолбец. Следующий вычисляющий скаляр умножает это на 5 и выдает столбец, вызываемый id5несмотря на то, что на этот столбец даже нет ссылки в запросе. Финальный скаляр вычислений принимает значение id5и выводит его как вызванный столбец id5p.

Использование флагов трассировки, описанных в Query Optimizer Deep Dive - часть 2 (отказ от ответственности: эти флаги трассировки не документированы / не поддерживаются) и анализ запроса

SELECT id5,
       id5p,
       ( id * 5 )
FROM   dbo.persist_test 
OPTION (QUERYTRACEON 3604, QUERYTRACEON 8606);

Дает вывод

Дерево перед нормализацией проекта

LogOp_Project

    LogOp_Get TBL: dbo.persist_test dbo.persist_test TableID=1717581157 TableReferenceID=0 IsRow: COL: IsBaseRow1002 

    AncOp_PrjList 

        AncOp_PrjEl QCOL: [tempdb].[dbo].[persist_test].id5

            ScaOp_Arithmetic x_aopMult

                ScaOp_Identifier QCOL: [tempdb].[dbo].[persist_test].id

                ScaOp_Const TI(int,ML=4) XVAR(int,Not Owned,Value=5)

        AncOp_PrjEl QCOL: [tempdb].[dbo].[persist_test].id5p

            ScaOp_Arithmetic x_aopMult

                ScaOp_Identifier QCOL: [tempdb].[dbo].[persist_test].id

                ScaOp_Const TI(int,ML=4) XVAR(int,Not Owned,Value=5)

        AncOp_PrjEl COL: Expr1004 

            ScaOp_Arithmetic x_aopMult

                ScaOp_Identifier QCOL: [tempdb].[dbo].[persist_test].id

                ScaOp_Const TI(int,ML=4) XVAR(int,Not Owned,Value=5)

Дерево после нормализации проекта

LogOp_Project

    LogOp_Get TBL: dbo.persist_test dbo.persist_test TableID=1717581157 TableReferenceID=0 IsRow: COL: IsBaseRow1002 

    AncOp_PrjList 

        AncOp_PrjEl QCOL: [tempdb].[dbo].[persist_test].id5

            ScaOp_Identifier QCOL: [tempdb].[dbo].[persist_test].id5

        AncOp_PrjEl QCOL: [tempdb].[dbo].[persist_test].id5p

            ScaOp_Identifier QCOL: [tempdb].[dbo].[persist_test].id5

        AncOp_PrjEl COL: Expr1004 

            ScaOp_Identifier QCOL: [tempdb].[dbo].[persist_test].id5

Таким образом, получается, что все определения вычисляемых столбцов расширяются, а затем на этапе нормализации проекта все идентичные выражения сопоставляются с вычисляемыми столбцами, и id5в этом случае это просто совпадает . то есть это не дает никакого предпочтения persistedколонке.

Если таблица воссоздается со следующим определением

CREATE TABLE dbo.persist_test (
      id            INT NOT NULL
    , id5p          AS (5 * id) PERSISTED
    , id5           AS (5 * id)
);

Затем запрос либо id5или id5pбудет удовлетворен, читая сохраненную версию данных , а не делать расчет во время выполнения , поэтому согласование , как представляется , произойдет (по крайней мере , в данном случае), чтобы колонки.

Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.