Qual efeito reduzirá o tamanho de uma coluna varchar no arquivo de banco de dados?

15

Temos várias tabelas em nosso banco de dados que possuem VARCHAR(MAX)colunas nas quais uma VARCHAR(500)(ou algo muito menor que max) será suficiente. Naturalmente, quero limpá-los e reduzir os tamanhos para níveis mais razoáveis. O 'como' fazer isso eu entendo: minha pergunta é o que alterar essas colunas fará com as páginas e as existentes no disco? (Existem muitas informações disponíveis sobre o que acontece quando você cresce uma coluna, mas com problemas para encontrar informações sobre o que acontece quando você reduz uma).

Algumas tabelas têm uma contagem de linhas muito pequena, então não estou preocupada com o custo da alteração, mas algumas são muito grandes e estou preocupada com a possibilidade de elas serem reorganizadas e causar muitos bloqueios / tempo de inatividade. Em termos práticos, eu só quero uma maneira de estimar uma janela de manutenção. Em geral, eu gostaria de entender melhor como o mecanismo de banco de dados se comporta nesse caso.

Desde já, obrigado!

EDITAR:

Eu tenho 20 tabelas que estou vendo, embora apenas metade delas tenha contagens de linhas maiores que 1.000. O maior tem quase um milhão de linhas. O pior infrator é uma tabela com 350.000 linhas e quatro VARCHAR(MAX)colunas que podem encolher para o VARCHAR(500)nível.

nateirvin
fonte

Respostas:

12

Primeiras coisas primeiro: quantos dados existem na tabela? Número de linhas e tamanho da tabela?

Segundo: você pode fazer backup e restaurar esta tabela em um servidor de teste e executar a instrução alter para ver o impacto (supondo que não seja inviável devido ao fato de a tabela ser muito grande para caber em um sistema não de produção)? Eu sempre acho que os testes no meu ambiente são mais precisos que os conselhos das interwebs, pois existem vários fatores que podem influenciar o resultado que talvez não seja fornecido na pergunta simplesmente por não saberem que esses fatores podem afetar o resultado.

Terceiro: aumentar o tamanho de um campo de tamanho variável é (supondo que você não ultrapasse o limite de 8060 bytes) uma operação simples de metadados, pois nenhum dado real estaria mudando para essa operação. Mas, por outro lado, reduzir o tamanho de um campo de tamanho variável, mesmo para algo que funcionará mais do que obviamente, não é uma simples alteração de metadados porque o SQL Server não sabe, antes da varredura de todas as linhas , que o tamanho solicitado recentemente é válido.

Portanto: Sim, isso bloqueará a tabela por um período de tempo . Quanto tempo? Bem, aqui está o teste que eu acabei de fazer:

Eu tinha, de algum outro teste, uma tabela com um único INT NOT NULLcampo e 1 milhão de linhas. Copiei-o para uma nova tabela com o objetivo de fazer este teste via:

SELECT *, CONVERT(NVARCHAR(MAX), NEWID()) AS [StringField]
INTO dbo.ResizeTest
FROM dbo.ClusteredUnique;

Dessa maneira, eu estava começando com um cenário semelhante de ter um MAXcampo (acabei de perceber que você tem VARCHARe estou usando NVARCHAR, mas isso não deve alterar o comportamento que estou vendo) para o qual eu poderia mudar 500. E possui dados que podem caber facilmente em 500 caracteres. Isso levou alguns minutos.

Eu então corri:

ALTER TABLE dbo.ResizeTest ALTER COLUMN [StringField] NVARCHAR(500) NULL;

E isso levou pouco mais de 11 minutos.

Eu apenas refiz o teste novamente, desta vez descartando a [ResizeTest]tabela e alterando os dois NVARCHARpara serem justos VARCHAR, apenas para ter certeza de que estou comparando maçãs com algo que pelo menos parece uma maçã ;-).

A criação da tabela inicial levou 20 segundos e ALTER TABLE2 minutos.

Portanto, em termos de estimativa do tempo de inatividade, isso é realmente difícil, pois se baseia na velocidade de E / S do disco, se alguma operação de crescimento automático precisa ou não ocorrer no arquivo de dados e / ou no log de transações, etc. é provavelmente uma grande parte do motivo pelo qual meu primeiro teste levou 11 minutos para ser alterado e o segundo, mesmo com VARCHARa metade do tamanho dos NVARCHARdados, levou apenas 2 minutos (ou seja, os arquivos foram pré-desenvolvidos nesse ponto). Ainda assim, lembre-se de que meu teste está sendo executado no meu laptop, que não é o disco mais rápido, mas também eram apenas 1 milhão de linhas de 2 colunas pequenas (22 ou mais bytes por linha).

E como você perguntou o que isso fará com as páginas de dados, aqui está sua resposta. Eu fiz um sp_spaceuseddepois de criar a tabela, depois de fazer o ALTER COLUMNe depois de fazer ALTER TABLE dbo.ResizeTest REBUILD;. Os resultados (os seguintes números são baseados no segundo teste usando VARCHAR, não no primeiro teste usando NVARCHAR):

After initial table creation:        526,344 KB
After ALTER COLUMN VARCHAR(500):   1,031,688 KB  <--- !! Yikes!!
After ALTER REBUILD:                 526,472 KB

Se você estiver preocupado com a necessidade de manter a operação no menor tempo possível, confira um artigo que escrevi sobre como fazer isso: Reestruture 100 milhões de linhas (ou mais) de tabelas em segundos. SRSLY! (é necessário registro gratuito).

Solomon Rutzky
fonte
2
Então, copiei a pior tabela para minha instância local (ou seja, disco mais lento e 1/3 dos núcleos). I ALTERed cada coluna em sucessão - cada ação levou menos de um segundo. Quando terminaram, a tabela havia dobrado de tamanho, mas depois que eu fiz uma REBUILD(que também era uma operação em um segundo), a tabela voltou ao tamanho original.
Nateirvin
@nateirvin É bom ouvir isso. Provavelmente, você pode acelerar a ALTER TABLEoperação executando todos os campos de uma só vez, separando cada coluna com uma vírgula. Se a transação for muito grande, divida a tabela em 2 instruções ALTER de metade das colunas cada. E, dependendo do tamanho da tabela, você pode até fazer uma REBUILD entre cada uma das duas instruções ALTER. Algo para brincar. Além disso, lembre-se de que a operação provavelmente terá um bloqueio de esquema pela duração que bloqueará todo o acesso à tabela.
Solomon Rutzky
1
Eu fiz cada um ALTERseparadamente para poder acompanhar as mudanças de tamanho entre cada um, mas definitivamente bom saber. Obrigado!
Nateirvin
1

Pelo que reuni executando a declaração alter não deve demorar muito, desde que a mesa não esteja bloqueada por outro processo. De acordo com o gbn, é apenas uma alteração de metadados: /programming/7261909/is-it-bad-to-use-alter-table-to-resize-a-varchar-column-to-a-larger -Tamanho

Além disso, quanto à maneira como eles são armazenados, parece que o SQL Server armazenou os dados do varchar em uma página de 8k até preencher uma página inteira, que neste momento o substitui por um ponteiro e os armazena como um BLOB.

Estou assumindo que quando você altera o comprimento, não estará truncando nenhum registro. Nesse caso, no máximo os dados que você está convertendo para varchar (500) devem ter no máximo 502 bytes e não devem ter um ponteiro.

Portanto, para encurtar a história, pouco deve mudar desde que você não esteja truncando nenhum dado.

DForck42
fonte
5
Isso é absolutamente incorreto. Não vou desistir porque você realmente o testou (o que é mais do que algumas pessoas fazem, então obrigado por fazer isso), mas você precisa testá-lo em escala. A resposta à qual você se vinculou foi aumentar o tamanho, não diminuir. Essas são duas operações muito diferentes.
Solomon Rutzky