Eu tenho uma tabela com linhas de 64m tomando 4,3 GB no disco para seus dados.
Cada linha tem cerca de 30 bytes de colunas inteiras, além de uma NVARCHAR(255)
coluna variável para texto.
Adicionei uma coluna NULLABLE com tipo de dados Datetimeoffset(0)
.
Atualizei essa coluna para cada linha e verifiquei se todas as novas inserções colocam um valor nessa coluna.
Como não havia entradas NULL, executei este comando para tornar meu novo campo obrigatório:
ALTER TABLE tblCheckResult
ALTER COLUMN [dtoDateTime] [datetimeoffset](0) NOT NULL
O resultado foi um enorme crescimento no tamanho do log de transações - de 6 GB para mais de 36 GB até ficar sem espaço!
Alguém tem alguma idéia do que o SQL Server 2008 R2 está fazendo para que esse comando simples resulte em um crescimento tão grande?
sql-server
sql-server-2008-r2
transaction-log
alter-table
null
PapillonUK
fonte
fonte
NOT NULL
coluna com um padrão como uma operação de metadados. Consulte também "Adicionando colunas NOT NULL como uma operação online" na documentação .Respostas:
Quando você altera uma coluna para NOT NULL, o SQL Server precisa tocar em todas as páginas, mesmo se não houver valores NULL. Dependendo do fator de preenchimento, isso pode levar a muitas divisões de página. É claro que todas as páginas tocadas precisam ser registradas, e suspeito que, devido às divisões, duas alterações possam ter que ser registradas para muitas páginas. Porém, como tudo é feito em uma única passagem, o log deve contabilizar todas as alterações para que, se você clicar em cancelar, saiba exatamente o que desfazer.
Um exemplo. Tabela simples:
Agora, vejamos os detalhes da página. Primeiro, precisamos descobrir com que página e DB_ID estamos lidando. No meu caso, criei um banco de dados chamado
foo
e o DB_ID passou a ser 5.A saída indicava que eu estava interessado na página 159 (a única linha na
DBCC IND
saída comPageType = 1
).Agora, vejamos alguns detalhes da página selecionados à medida que avançamos no cenário do OP.
Agora, eu não tenho todas as respostas para isso, porque eu não sou um cara interno profundo. Mas é claro que - embora a operação de atualização e a adição da restrição NOT NULL sejam inegavelmente gravadas na página - a última o faz de uma maneira totalmente diferente. Parece realmente alterar a estrutura do registro, em vez de apenas mexer nos bits, trocando a coluna anulável por uma coluna não anulável. Por que isso precisa ser feito, não tenho muita certeza - uma boa pergunta para a equipe do mecanismo de armazenamento , eu acho. Acredito que o SQL Server 2012 lida com alguns desses cenários muito melhor, FWIW - mas ainda não fiz testes exaustivos.
fonte
Ao executar o comando
Isso parece ser implementado como uma operação Adicionar coluna, Atualizar, Soltar coluna.
sys.sysrscols
para representar uma nova coluna. Ostatus
bit para128
é definido, indicando que a coluna não permiteNULL
ssys.sysrscols
.rscolid
Atualizada para um número inteiro grande e ostatus
bit 2 ativado como descartado indicado)sys.sysrscols
para a nova coluna é alterada para fornecer arscolid
da coluna antiga.A operação com potencial para causar muitos logs é a
UPDATE
de todas as linhas da tabela, no entanto, isso não significa que isso sempre ocorra. Se as imagens "antes" e "depois" da linha forem idênticas, isso será tratado como uma atualização sem atualização e não será registrado nos meus testes até o momento.Portanto, a explicação do motivo pelo qual você está obtendo muitos logs dependerá do motivo pelo qual exatamente as versões "antes" e "depois" da linha não são as mesmas.
Para colunas de comprimento variável armazenadas no
FixedVar
formato, achei que a configuraçãoNOT NULL
sempre causa uma alteração na linha que precisa ser registrada. A contagem de colunas e a contagem de colunas de comprimento variável são incrementadas e a nova coluna é adicionada ao final da seção de comprimento variável duplicando os dados.datetimeoffset(0)
é de comprimento fixo, no entanto, e para colunas de comprimento fixo armazenadas noFixedVar
formato, as colunas antigas e novas parecem receber o mesmo slot na parte de dados de comprimento fixo da linha e, pois ambas têm o mesmo comprimento e valorizam o "antes" e As versões "depois" da linha são iguais . Isso pode ser visto na resposta de @ Aaron. Ambas as versões da linha antes e depois daALTER TABLE dbo.floob ALTER COLUMN bar INT NOT NULL;
sãoIsto não está registrado.
Logicamente, a partir da minha descrição de eventos, a linha deve de fato ser diferente aqui, pois a contagem de colunas
02
deve ser aumentada para,03
mas nenhuma alteração realmente ocorre na prática.Algumas razões possíveis para isso ocorrer em uma coluna de comprimento fixo são:
SPARSE
a nova coluna seria armazenada em uma parte diferente da linha da original, fazendo com que as imagens da linha anterior e posterior fossem diferentes.ALTER TABLE
operação anterior que foi implementada como uma alteração apenas de metadados e ainda não foi aplicada à linha. Por exemplo, se uma nova coluna de comprimento variável anulável foi adicionada, ela é aplicada originalmente como uma alteração apenas de metadados e, na verdade, é gravada apenas nas linhas na próxima atualização (a gravação que realmente ocorre nesta última instância é apenas atualização para seção contagem de colunas eNULL_BITMAP
como umaNULL
varchar
coluna no final da linha não ocupa qualquer espaço)fonte
Eu enfrentei o mesmo problema em uma tabela com 200.000.000 de linhas. Inicialmente, adicionei a coluna anulável, atualizei todas as linhas e, finalmente, alterei a coluna por
NOT NULL
meio de umaALTER TABLE ALTER COLUMN
instrução Isso resultou em duas grandes transações explodindo o arquivo de log incrivelmente (crescimento de 170 GB).A maneira mais rápida que encontrei foi a seguinte:
Adicione a coluna usando um valor padrão
Elimine a restrição padrão usando o SQL dinâmico, pois a restrição não foi nomeada antes:
O tempo de execução caiu de> 30 minutos para 10 minutos, incluindo a replicação das alterações via Replicação Transacional. Estou executando uma instalação do SQL Server 2008 (SP2).
fonte
Eu executei o seguinte teste:
Acredito que isso tenha a ver com o espaço reservado que o log mantém para o caso de você reverter a transação. Procure na função fn_dblog na coluna 'Reserva de Log' a linha LOP_BEGIN_XACT e veja quanto espaço está tentando reservar.
fonte
select * FROM fn_dblog(null, null) where AllocUnitName='dbo.tblCheckResult' AND Operation = 'LOP_MODIFY_ROW'
poderá ver as 10000 atualizações de linha.O comportamento para isso é diferente no SQL Server 2012. Consulte http://rusanu.com/2011/07/13/online-non-null-with-values-column-add-in-sql-server-11/
O número de registros de log gerados para o SQL Server 2008 R2 e versões posteriores será significativamente maior que o número de registros de log do SQL Server 2012.
fonte
NOT NULL
causar log. A mudança em 2012 é sobre adicionar uma novaNOT NULL
coluna com um padrão.