Creación de índice no agrupado en una columna computada no persistente SQL Server

10

Me cuesta encontrar documentación sobre cómo SQL Server realmente almacena una columna calculada no persistente.

Tome el siguiente ejemplo:

--SCHEMA
CREATE TABLE dbo.Invoice
(
    InvoiceID INT IDENTITY(1, 1) PRIMARY KEY,
    CustomerID INT FOREIGN KEY REFERENCES dbo.Customer(CustomerID),
    InvoiceStatus NVARCHAR(50) NOT NULL,
    InvoiceStatusID AS CASE InvoiceStatus 
                         WHEN 'Sent' THEN 1 
                         WHEN 'Complete' THEN 2
                         WHEN 'Received' THEN 3
                       END
)
GO

--INDEX
CREATE NONCLUSTERED INDEX IX_Invoice ON Invoice
(
    CustomerID ASC
)
INCLUDE
(
    InvoiceStatusID
)
GO

Entiendo que se almacena a nivel de hoja, pero si el valor no se conserva, ¿cómo se almacena algo? ¿Cómo ayuda el índice a SQL Server a encontrar estas filas en esta situación?

Cualquier ayuda muy apreciada,

Muchas gracias,

EDITAR:

Gracias a Brent y Aaron por responder esto, aquí está el PasteThePlan que muestra claramente lo que explicaron.

Uberzen1
fuente
55
No se conserva en las páginas de datos de la tabla, pero sí en las páginas del índice .
Aaron Bertrand
Las columnas calculadas no persistentes no se almacenan físicamente en la tabla. Son columnas virtuales. Sus valores se vuelven a calcular cada vez que se hace referencia en una consulta. ver esta ref .
Kin Shah

Respuestas:

11

Cuando SQL Server crea el índice en el campo calculado, el campo calculado se escribe en el disco en ese momento, pero solo en las páginas de 8K de ese índice. SQL Server puede calcular el InvoiceStatusID a medida que lee el índice agrupado; no es necesario escribir esos datos en el índice agrupado.

A medida que borra / actualiza / inserta filas en dbo.Invoice, los datos en los índices se mantienen actualizados. (Cuando InvoiceStatus cambia, SQL Server también debe actualizar IX_Invoice).

La mejor manera de ver esto es hacerlo: crear estos objetos y ejecutar actualizaciones que toquen el campo InvoiceStatusID. Publique el plan de ejecución (PasteThePlan.com es útil para esto) si desea ayuda para ver dónde están ocurriendo las actualizaciones del índice.

Brent Ozar
fuente
1
@ Uberzen1 No, como explicó, está escrito en las páginas de índice en el momento de inserción / actualización. No tiene que volver a calcular nada si el índice se utiliza para acceder a la columna.
Aaron Bertrand
Ah! Estoy contigo ahora, lo siento!
Uberzen1
66
@blobbles bien, sin ofender, pero no creo que eso esté en Brent. Podrían pegar ese mismo XML en Dropbox, foros de MSDN, aquí, básicamente en cualquier lugar en línea ... ¿todos los servicios en línea ahora deben ser responsables de los secretos que podrían divulgar las personas que cargan archivos allí?
Aaron Bertrand
2
@blobbles sí, simplemente no puedes evitar que la gente comparta demasiado. Hola, por cierto, sígueme en Instagram, soy BrentO, y comparto fotos de mi desayuno allí. ;-)
Brent Ozar
44
@blobbles en el enlace Privacidad, dice: Los datos que copia / pega aquí son públicos . Cualquiera puede leerlo. No hay seguridad
ypercubeᵀᴹ
8

El valor de una columna calculada indexada y no persistente no se conserva en las páginas de datos de la tabla , pero sí en las páginas del índice . Permanece sin persistencia en la tabla, independientemente de si persiste en 0, 1 o múltiples índices.

Solo para ilustrar la descripción de Brent, tomando el ejemplo que dio, insertemos una fila:

INSERT dbo.Invoice(CustomerID, InvoiceStatus) VALUES(1,N'Sent');

Ahora, veamos las páginas de índice:

DBCC TRACEON(3604, -1);
DBCC IND(N'dbname', N'dbo.Invoice', 2);

(Obviamente dbname, cambie , y la ID del índice podría no ser 2 en su caso).

Salida (la suya seguramente será diferente):

ingrese la descripción de la imagen aquí

Y finalmente, inspeccionemos la página para PageType2:

DBCC PAGE(7, 1, 584, 3);

(Es probable que necesite cambiar 7 para que coincida con la identificación de su base de datos, y si tiene varios archivos de datos, es posible que deba cambiar el segundo argumento para que coincida PageFIDcon el primer resultado).

Salida:

ingrese la descripción de la imagen aquí

Eso está en la página de índice.

Aaron Bertrand
fuente
Muy bien, gracias Aaron. La razón por la que hice la pregunta inicialmente es que estoy teniendo problemas reales para implementar un índice similar en el mundo real, y quería entender exactamente lo que está sucediendo debajo del capó para poder resolver el problema. Esto ayuda mucho, gracias!
Uberzen1
1
@ Uberzen1 ¿Puedes definir "problema real"? ¿Vas a publicar una pregunta sobre ese problema?
Aaron Bertrand
Puedo hacerlo, primero iba a profundizar un poco más, pero solo quería entender qué está haciendo exactamente la declaración de creación de índice. El TLDR es; Tengo una tabla grande similar a la tabla de facturas anterior, tiene alrededor de 400m de registros y, desafortunadamente, la columna OrderStatus se colocó justo en el medio, lo que hace que la indexación, etc. sea un poco dolorosa. Hemos agregado una columna calculada por ahora que eventualmente persistiremos y moveremos el campo varchar a su propia tabla. 1/2
Uberzen1
55
@ Uberzen1 Sí, debido a que la columna calculada se materializa en el disco cuando se escribe en el índice, toda esa actividad debe registrarse. Una solución alternativa podría ser dejar de depender de la columna calculada, ya sea poner esa expresión en una vista o en las consultas ad hoc, y si esa no es una opción, podría hacer una nueva columna anulable, actualizarla en fragmentos (para evitar la destrucción del registro) , luego suelte la columna calculada, cambie el nombre de la nueva columna y cambie su DML para escribir eso manualmente. Pero realmente, dado que es información redundante que puede derivar de los datos existentes, optaría por la primera opción.
Aaron Bertrand
2
Muchas gracias Aaron. Me alegra que hayas mencionado poner una vista frente a él, ya que esa también fue mi solución, ¡tal vez es hora de revisar esa idea!
Uberzen1
7

El atributo PERSISTEDpara una columna calculada se refiere a si los valores persisten en la tabla (índice agrupado o montón) y no a si los valores persisten en el índice.

El CREATE INDEXtiene los requisitos para las limitaciones en cuanto a las columnas y los índices calculados:

Las columnas calculadas que son deterministas y precisas o imprecisas pueden incluirse columnas. Las columnas calculadas derivadas de los tipos de datos image, ntext, text, varchar (max), nvarchar (max), varbinary (max) y xml pueden incluirse en columnas sin clave siempre que los tipos de datos de columna computados sean permitidos como incluidos columna. Para obtener más información, vea Índices en columnas calculadas.

No hay limitación sobre si la columna calculada es persistente o no.

y más (no se trata de columnas incluidas sino de columnas calculadas en la parte principal de un índice):

Los índices se pueden crear en columnas calculadas. Además, las columnas calculadas pueden tener la propiedad PERSISTED. Esto significa que el Motor de base de datos almacena los valores calculados en la tabla y los actualiza cuando se actualizan cualesquiera otras columnas de las que depende la columna calculada. El Motor de base de datos utiliza estos valores persistentes cuando crea un índice en la columna y cuando se hace referencia al índice en una consulta.

Para indexar una columna calculada, la columna calculada debe (ser) determinista y precisa. Sin embargo, el uso de la PERSISTEDpropiedad expande el tipo de columnas calculadas indexables para incluir:

...

ypercubeᵀᴹ
fuente