Por que o SQL Server “computa escalar” quando seleciono uma coluna computada persistente?

21

As três SELECTinstruções neste código

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;

gere este plano:

plano de execução

Por que o final SELECT, que está selecionando um valor persistente, gera um operador Escalar de computação ?

Nick Chammas
fonte
3
Veja a resposta do @ SqlKiwi aqui: Por que o Plano de Execução inclui uma chamada de função definida pelo usuário para uma coluna computada que é mantida? . Na sua consulta, a lista da coluna de saída da tabela é apenas [tempdb].[dbo].[persist_test].ide calcula o valor apesar de persistir.
Martin Smith

Respostas:

14

Apenas para resumir as descobertas experimentais nos comentários, este parece ser um caso extremo que ocorre quando você tem duas colunas computadas na mesma tabela, uma persistede uma não persistiram e ambas têm a mesma definição.

No plano para a consulta

SELECT id5p
FROM dbo.persist_test;

A varredura da tabela persist_testemite apenas a idcoluna. O próximo escalar de computação multiplica isso por 5 e gera uma coluna chamada, id5apesar do fato de essa coluna nem sequer ser referenciada na consulta. O escalar final de computação leva o valor de id5e gera como uma coluna chamada id5p.

Usando os sinalizadores de rastreamento explicados no Query Optimizer Deep Dive - Parte 2 (isenção de responsabilidade: esses sinalizadores de rastreamento não são documentados / não são suportados) e examinando a consulta

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

Dá a saída

Árvore antes da normalização do projeto

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)

Árvore após a normalização do projeto

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

Portanto, parece que todas as definições de coluna computadas são expandidas e, durante o estágio de Normalização do Projeto, todas as expressões idênticas são correspondidas novamente às colunas computadas e, por acaso, coincide id5nesse caso. isto é, não dá nenhuma preferência à persistedcoluna.

Se a tabela for recriada com a seguinte definição

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

Em seguida, uma solicitação para id5ou id5pserá satisfeita pela leitura da versão persistente dos dados, em vez de fazer o cálculo no tempo de execução, para que a correspondência pareça ocorrer (pelo menos nesse caso) na ordem das colunas.

Martin Smith
fonte