Pourquoi SQL Server «calcule-t-il scalaire» lorsque je sélectionne une colonne calculée persistante?


21

Les trois SELECTdéclarations de ce code

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;

générer ce plan:

plan d'exécution

Pourquoi la finale SELECT, qui sélectionne une valeur persistante, génère-t-elle un opérateur de calcul scalaire ?


3
Voir la réponse de @ SqlKiwi ici: Pourquoi le plan d'exécution inclut-il un appel de fonction défini par l'utilisateur pour une colonne calculée persistante? . Dans votre requête, la liste des colonnes de sortie de la table est uniquement [tempdb].[dbo].[persist_test].idet elle calcule la valeur malgré sa persistance.
Martin Smith

Réponses:


14

Juste pour résumer les résultats expérimentaux dans les commentaires, cela semble être un cas extrême qui se produit lorsque vous avez deux colonnes calculées dans la même table, une persistedet une non persistante et qu'elles ont toutes les deux la même définition.

Dans le plan de la requête

SELECT id5p
FROM dbo.persist_test;

L'analyse de la table sur persist_testn'émet que la idcolonne. Le prochain calcul scalaire multiplie cela par 5 et génère une colonne appelée id5malgré le fait que cette colonne n'est même pas référencée dans la requête. Le scalaire de calcul final prend la valeur de id5et affiche cette valeur sous la forme d'une colonne appelée id5p.

Utilisation des indicateurs de trace expliqués dans Query Optimizer Deep Dive - Partie 2 (avertissement: ces indicateurs de trace sont non documentés / non pris en charge) et en regardant la requête

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

Donne la sortie

Arborescence avant la normalisation du projet

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)

Arborescence après la normalisation du projet

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

Il apparaît donc que toutes les définitions de colonnes calculées sont développées, puis pendant la phase de normalisation du projet, toutes les expressions identiques sont mises en correspondance avec les colonnes calculées et il se trouve que cela correspond id5dans ce cas. c'est-à-dire qu'il ne donne aucune préférence à la persistedcolonne.

Si la table est recréée avec la définition suivante

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

Ensuite, une demande pour id5ou id5psera satisfaite en lisant la version persistante des données plutôt qu'en effectuant le calcul au moment de l'exécution, de sorte que la correspondance semble se produire (au moins dans ce cas) dans l'ordre des colonnes.

En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.