Decimal do SQL Server (9, 0) vs INT

15

Um de nossos clientes usa para algumas colunas o tipo de dados DECIMAL(18,0)em seu banco de dados SQL Server 2008R2. Como as colunas crescem muito lentamente, ele recentemente propôs alterar o tipo de dados DECIMAL(5,0)para recuperar algum armazenamento.

De acordo com a biblioteca do MSDN , o espaço de armazenamento do DECIMAL(5,0)tipo de dados é, assim como o DECIMAL(9,0)tipo de dados, 5 bytes. INTé 1 byte menor, mas pode armazenar tudo no intervalo de -2 ^ 31 a 2 ^ 31 em vez dos -99.999 a 99.999 que DECIMAL(5,0)podem ser armazenados. Mesmo o maior DECIMALque se encaixa em 5 bytes ( DECIMAL(9,0)) pode armazenar apenas números inteiros no intervalo -999.999.999 a 999.999.999 (que é menos da metade da faixa INToferecida em 4 bytes).

Posso pensar em dois "benefícios" do uso DECIMALexcessivo INT:

  • A capacidade de adicionar escala posteriormente, sem usar mais espaço de armazenamento
  • A capacidade de escalar a precisão em até 38 dígitos, sem alterar o tipo de dados

mas estes não são benefícios reais na minha opinião:

  • Adicionar escala a números inteiros só faz sentido em muito poucos casos (na maioria dos casos em que a escala faz diferença, ela também pode ser adicionada com antecedência)
  • O SQL Server vê cada combinação de precisão / escala como um tipo de dados diferente; portanto, o tipo de dados não é deixado sozinho ao aumentar a precisão ou a escala.

Isso me faz pensar: qual é o benefício adicional de um DECIMAL(5,0)tipo de dados para números inteiros?

vstrien
fonte
1
Um benefício pode ser o limite de cinco dígitos. Mas me pergunto quanto espaço de armazenamento você pode economizar com essa mudança.
Dez16
3
IMO, se você só precisa garantir que os valores da coluna estejam dentro de um intervalo, use uma restrição de verificação. Eu acho que a única consideração aqui seria se existe a possibilidade dessa coluna exigir valores fracionários no futuro.
22812 Jon Seigel
3
Se eles estão preocupados com o espaço de armazenamento, eles são mais adequados para a compressão do que isso. Não há benefício tangível em usar decimal (x, 0) em vez de int / bigint.
22812 Robert L Davis
7
Outra diferença entre decimal(x,0)e um tipo inteiro mostra-se na divisão aritmética. Se você dividir um int por um int, você obtém um int. Se você dividir um decimal (x, 0) por um int, obtém um decimal (x + 6,6).
Andriy M
@AndriyM, acho que esse é o maior benefício. Reformule-o em uma resposta em vez de em um comentário e eu vou marcá-lo como resposta.
vstrien

Respostas:

8

Concordo que não há benefícios reais em termos de espaço de armazenamento , desde que você esteja comparando DECIMAL (9, 0) vs INT ou DECIMAL (18, 0) vs BIGINT. (Dentro de um único byte.)

Em termos de processamento, como @Andriy diz que o DECIMAL se dividirá naturalmente em um tipo que não perde a parte fracionária, se isso for importante para você.

Por outro lado, trabalhar com tipos INT nativos é muito mais rápido do ponto de vista numérico, se você estiver fazendo muitas SUM () s ou comparações (como pesquisar nos valores), pois elas são canalizadas com mais eficiência pela CPU. Uma comparação int são dois códigos de montagem (MOV, CMP), mas qualquer comparação decimal será muito, muito mais.

Chris Chubb
fonte
Sua resposta faz sentido, mas um processador não tem nenhum conhecimento de tipos de dados. Portanto, um tipo de dados de 4 bytes é comparado tão rápido quanto outro tipo de dados de 4 bytes. Você pode mostrar (com um teste de desempenho repetitivo, por exemplo) que há um impacto no desempenho ao DECIMAL(9, 0)invés de um INT?
vstrien
2
Eu pensei que poderia, mas vou admitir que meus testes são inconclusivos. Talvez o SQL esteja fazendo uma otimização para reduzir o problema à matemática inteira. Meu testbed: `- Comparação interna SET @StartTime = SYSDATETIME () ENQUANTO (@CounterINT <@SizeINT) SET @CounterINT = @CounterINT + 1 PRINT 'INT levou' + CONVERT (VARCHAR (20), DATEDIFF (milissegundos, @StartTime , SYSDATETIME ())) + 'milissegundos' --Decimal SET @StartTime = SYSDATETIME () ENQUANTO (@CounterDEC <@SizeDEC) SET @CounterDEC = @CounterDEC + 1 PRINT 'DEC taken' + CONVERT (VARCHAR (20), DATEDIFF (milissegundo, @StartTime, SYSDATETIME ())) + 'milissegundos' '
Chris Chubb
Eu acho que o SQL Server otimiza algo lá de fato. Apesar da otimização DECIMALainda demorar um pouco mais (pelo menos no meu sistema de desenvolvimento). Em uma execução de 10 testes em torno de 51 ms DEC vs. 46 ms INT.
vstrien
2

Parece que não haverá benefícios em termos de espaço de armazenamento.

Se o seu cliente está preocupado com o fato de seus valores serem maiores que 2 ^ 32-1 (o valor máximo positivo inteiro pode armazenar), você deve considerar a mudança para BigInt - com 64 bits ( 8 bytes) .

AlexTheDeveloper
fonte