Criando índice não clusterizado no SQL Server de coluna computada não persistente

10

Estou com dificuldades para encontrar qualquer documentação sobre como o SQL Server realmente armazena uma coluna computada não persistente.

Veja o seguinte exemplo:

--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

Eu entendo que ele é armazenado no nível da folha, mas se o valor não for persistente, como algo é armazenado? Como o índice ajuda o SQL Server a encontrar essas linhas nessa situação?

Qualquer ajuda muito apreciada,

Muito Obrigado,

EDITAR:

Obrigado a Brent & Aaron por responderem, aqui está o PasteThePlan mostrando claramente o que eles explicaram.

Uberzen1
fonte
5
Ele não persiste nas páginas de dados da tabela, mas nas páginas do índice .
Aaron Bertrand
As colunas computadas não persistentes não são fisicamente armazenadas na tabela. Eles são colunas virtuais. Seus valores são recalculados toda vez que são referenciados em uma consulta. veja esta ref .
Kin Shah

Respostas:

11

Quando o SQL Server cria o índice no campo computado, o campo computado é gravado no disco naquele momento - mas apenas nas páginas de 8K desse índice. O SQL Server pode calcular o InvoiceStatusID conforme ele lê o índice em cluster - não há necessidade de gravar esses dados no índice em cluster.

À medida que você exclui / atualiza / insere linhas no dbo.Invoice, os dados nos índices são mantidos atualizados. (Quando InvoiceStatus é alterado, o SQL Server também sabe atualizar IX_Invoice.)

A melhor maneira de ver isso por si mesmo é realmente fazê-lo: crie esses objetos e execute atualizações que tocam no campo InvoiceStatusID. Poste o plano de execução (PasteThePlan.com é útil para isso) se desejar ajuda para ver onde as atualizações do índice estão acontecendo.

Brent Ozar
fonte
11
@ Uberzen1 Não, como ele explicou, ele é gravado nas páginas de índice no momento da inserção / atualização. Não é necessário recalcular nada se o índice for usado para acessar a coluna.
Aaron Bertrand
Ah! Estou com você agora, desculpe!
usar o seguinte código
6
@ blobbles bem, sem ofensas, mas não acho que isso seja do Brent. Eles poderiam colar o mesmo XML no dropbox, nos fóruns do MSDN, aqui, basicamente em qualquer lugar on-line ... agora todo serviço on-line precisa ser responsável por segredos que podem ser divulgados por pessoas que enviam arquivos para lá?
Aaron Bertrand
2
@blobbles sim, você simplesmente não pode impedir as pessoas de compartilhar demais. Ei, a propósito, siga-me no Instagram - eu sou BrentO - e compartilho fotos do meu café da manhã lá. ;-)
Brent Ozar
4
@blobbles no link Privacidade, afirma: Os dados que você copia / cola aqui são públicos . Qualquer um pode ler. Não há segurança.
precisa saber é o seguinte
8

O valor para uma coluna computada indexada e não persistente não é persistente nas páginas de dados da tabela , mas é persistido nas páginas do índice . Ele permanece sem persistência na tabela, independentemente de persistir em 0, 1 ou em vários índices.

Apenas para ilustrar a descrição de Brent, tomando o exemplo que você deu, vamos inserir uma linha:

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

Agora, vamos ver as páginas de índice:

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

(Obviamente dbname, mude e o ID do índice pode não ser 2 no seu caso.)

Saída (a sua certamente será diferente):

insira a descrição da imagem aqui

E, finalmente, vamos inspecionar a página para PageType2:

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

(Você provavelmente precisará alterar 7 para corresponder ao seu ID do banco de dados e, se tiver vários arquivos de dados, poderá ser necessário alterar o segundo argumento para corresponder PageFIDao primeiro resultado.)

Resultado:

insira a descrição da imagem aqui

Está na página de índice.

Aaron Bertrand
fonte
Muito legal, obrigado Aaron. A razão pela qual eu fiz a pergunta inicialmente é que estou tendo problemas reais para implantar um índice semelhante no mundo real e queria entender exatamente o que está acontecendo sob o capô para que eu possa resolver o problema. Isso ajuda muito, obrigado!
usar o seguinte código
11
@ Uberzen1 Você pode definir "problemas reais"? Você vai postar uma pergunta sobre esse problema?
Aaron Bertrand
Posso fazê-lo, eu iria me aprofundar um pouco mais, mas só queria entender o que exatamente a instrução create index está fazendo. O TLDR é; Eu tenho uma tabela grande semelhante à tabela de faturas acima, ela tem cerca de 400m de registros e, infelizmente, a coluna OrderStatus bateu bem no meio dela, tornando a indexação etc. um pouco dolorosa. Nós adicionamos uma coluna computada por enquanto que, eventualmente, persistiremos e moveremos o campo varchar para sua própria tabela. 1/2
Uberzen1
5
@ Uberzen1 Sim, porque a coluna computada é realmente materializada no disco ao gravar no índice, toda essa atividade deve ser registrada. Uma solução alternativa pode ser parar de confiar na coluna computada - coloque essa expressão em uma exibição ou nas consultas ad hoc e, se essa não for uma opção, você poderá criar uma nova coluna anulável, atualize-a em pedaços (para evitar a interrupção do registro) , solte a coluna computada, renomeie a nova coluna e altere seu DML para escrever isso manualmente. Mas, na verdade, como são informações redundantes que você pode derivar dos dados existentes, eu optaria pela primeira opção.
Aaron Bertrand
2
Muito obrigado Aaron. Fico feliz que você tenha mencionado colocar uma visão em frente, pois essa também foi minha solução, talvez seja hora de revisitar essa ideia!
usar o seguinte código
7

O atributo PERSISTEDpara uma coluna computada refere-se à persistência dos valores na tabela (índice clusterizado ou heap) e não à persistência dos valores no índice.

O CREATE INDEXpossui os requisitos para as limitações relacionadas a colunas e índices calculados:

Colunas computadas que são determinísticas e precisas ou imprecisas podem ser incluídas colunas. As colunas computadas derivadas dos tipos de dados imagem, ntext, texto, varchar (max), nvarchar (max), varbinary (max) e xml podem ser incluídas em colunas não-chave, desde que os tipos de dados da coluna computada sejam permitidos como incluídos coluna. Para mais informações, consulte Índices em colunas computadas.

Não há limitação se a coluna computada é mantida ou não.

e mais (não sobre as colunas incluídas, mas sobre as calculadas na parte principal de um índice):

Os índices podem ser criados em colunas computadas. Além disso, colunas computadas pode ter a propriedade PERSISTED. Isso significa que o Mecanismo de Banco de Dados armazena os valores calculados na tabela e os atualiza quando quaisquer outras colunas das quais a coluna calculada depende são atualizadas. O Mecanismo de Banco de Dados usa esses valores persistentes quando cria um índice na coluna e quando o índice é referenciado em uma consulta.

Para indexar uma coluna computada, a coluna computada deve (ser) determinística e precisa. No entanto, o uso da PERSISTEDpropriedade expande o tipo de colunas computáveis ​​indexáveis ​​para incluir:

...

ypercubeᵀᴹ
fonte