Чому 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;

генеруйте цей план:

план виконання

Чому фінал SELECT, який вибирає збережене значення, генерує оператор Обчислювальний скаляр ?


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

Відповіді:


14

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

У плані запиту

SELECT id5p
FROM dbo.persist_test;

Сканування таблиці persist_testвидає лише idстовпець. Наступний скаляр обчислень помножує на 5 і виводить стовпчик, що викликається, id5незважаючи на те, що цей стовпець навіть не посилається в запиті. Кінцевий скаляр обчислення вздовж приймає значення id5та виводить, що називається стовпцем id5p.

Використання прапорів слідів, пояснених в Deep Dive Dive 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.