Preciso criar uma ampla tabela desnormalizada com muitas colunas decimais (26,8) (limite inferior a 1024, a maioria das colunas seria nula ou zero). Eu sei sobre 8060 bytes por limitação de linha, então tentei criar tabela com compactação de página. O código abaixo cria a tabela, insere uma linha e consulta o tamanho da linha. O tamanho da linha está muito abaixo do limite, mas se eu tentar adicionar mais uma coluna decimal (26,8) à tabela, a operação falhará com o erro "A criação ou alteração da tabela 't1' falhou porque o tamanho mínimo da linha seria 8074, incluindo 1256 bytes de sobrecarga interna. " Existe alguma maneira de criar tabela única com tantas colunas?
drop table t1
GO
create table t1(c1 decimal(26, 8) null)
with (data_compression = page)
GO
declare @i int = 2;
declare @sql varchar(100);
while @i <= 486
begin
set @sql = 'alter table t1 add c' + convert(varchar, @i) + ' decimal(26, 8) null';
execute (@sql);
set @i += 1;
end;
GO
insert into t1(c1) select 0
GO
declare @i int = 2;
declare @sql varchar(100);
while @i <= 486
begin
set @sql = 'update t1 set c' + convert(varchar, @i) + ' = 0';
execute (@sql);
set @i += 1;
end;
GO
select max_record_size_in_bytes from sys.dm_db_index_physical_stats (db_id(), object_id('t1'), NULL, NULL, 'DETAILED')
GO
DECIMAL(26, 8) NULL
campos em uma tabela, sem compactação de página ou compactação decimal. Ativando a compactação vardecimal, mas não a página, a sobrecarga salta para mais de 1 K. Há uma chance externa de que você possa armazenar mais campos por página sem vardecimal, dependendo dos seus valores.Respostas:
O limite que você está enfrentando não tem nada a ver com os dados armazenados na página. O cálculo é feito com base nos tipos de dados das colunas. É por isso que você encontra o erro sem nenhum dado na tabela. A compactação torna esse limite pior. Você pode ler sobre os detalhes técnicos por trás da sobrecarga aqui .
Você pode solucionar esse problema usando colunas SPARSE . Isso significa que será possível que as inserções falhem, dependendo do que você inserir, mas você pode ignorar o limite de 8060 bytes. O código a seguir mostra que você pode criar 1023 colunas corretamente:
No entanto, todas as restrições ao seu redor (leia o artigo vinculado) podem tornar isso inadequado para o seu caso de uso. Especificamente, apenas
NULL
valores (não0
) são otimizados para ocupar muito pouco espaço. Se você tentar inserir muitos0
s em uma única linha, receberá um erro. Aqui está o que vejo quando tento inserir0
valores 1023 :Suponho que, se você ficou realmente desesperado, pode criar as colunas como
VARCHAR(27)
alternativa. As colunas de comprimento variável podem ser movidas para fora da página para que você possa exceder o limite de 8060 bytes na definição da tabela, mas a inserção de certas combinações de valores falhará. O SQL Server avisa sobre isso ao criar a tabela:A compactação de página ou linha pode ser útil se você seguir a
VARCHAR(27)
abordagem. Isso minimizará o espaço usado por ambos0
eNULL
. ComVARCHAR(27)
eu sou capaz de inserir 10230
valores muito bem.fonte
Fora dos aspectos técnicos e da solução alternativa proposta (usando
VARCHAR(27)
colunas) discutidos na resposta de @ Joe , questiono a " necessidade de criar [uma] ampla tabela desnormalizada" conforme expressa pelo OP A menos que haja algum requisito técnico estranho de que todas essas colunas deve estar em uma única tabela, eu sugeriria / recomendaria espalhá-las por quantas tabelas de "irmãos" forem necessárias. Tabelas de irmãos sendo tabelas que:IDENTITY
coluna (e nenhum FK para os outros)IDENTITY
Aqui você está dividindo a linha lógica em duas ou mais tabelas físicas. Mas isso é essencialmente o que é normalização, e quais bancos de dados relacionais são projetados para lidar.
Nesse cenário, você incorre em espaço extra usado pela duplicação da PK e em alguma complexidade adicional de consulta devido à necessidade de
INNER JOIN
juntar as tabelas (frequentemente, mas nem sempre, a menos que todas asSELECT
consultas usem todas as colunas, mas isso geralmente não acontece) ou criar uma transação explícita aINSERT
ouUPDATE
-los juntos (DELETE
pode ser tratada atravésON DELETE CASCADE
set no FK).NO ENTANTO, você obtém os benefícios de ter um modelo de dados adequado com tipos de dados nativos adequados e nenhum truque que possa ter consequências imprevisíveis posteriormente. Mesmo que o uso
VARCHAR(27)
permita que isso funcione em um nível técnico, pragmaticamente, não acho que armazenar decimais como seqüências de caracteres seja do seu interesse / do projeto.Portanto, se você estiver apenas "precisando" de uma única tabela devido a não perceber que uma única entidade lógica não precisa ser representada fisicamente em um único contêiner, não tente forçar tudo isso em uma única tabela quando ela funcionar. graciosamente em várias tabelas.
O exemplo abaixo ilustra o conceito básico:
CONFIGURAÇÃO
TESTE
Devoluções:
fonte