SQL Server Decimal (9, 0) vs INT

15

Un de nos clients utilise pour certaines colonnes le type DECIMAL(18,0)de données dans sa base de données SQL Server 2008R2. Parce que les colonnes croissent assez lentement, il a récemment proposé de changer le type de données DECIMAL(5,0)pour retrouver un peu de stockage.

Selon la bibliothèque MSDN , l'espace de stockage du DECIMAL(5,0)type de données est, tout comme le DECIMAL(9,0)type de données, de 5 octets. INTest 1 octet plus petit, mais peut tout stocker dans la plage de -2 ^ 31 à 2 ^ 31 au lieu des -99 999 à 99 999 qui DECIMAL(5,0)peuvent le stocker. Même le plus grand DECIMALqui tient en 5 octets ( DECIMAL(9,0)) ne peut stocker que des entiers compris entre -999 999 999 et 999 999 999 (ce qui représente moins de la moitié de la plage INTproposée en 4 octets).

Je peux penser à deux «avantages» de l'utilisation de DECIMALplus INT:

  • La possibilité d'ajouter de l'échelle par la suite, sans utiliser plus d'espace de stockage
  • La possibilité de mettre à l'échelle la précision jusqu'à 38 chiffres, sans modifier le type de données

mais ce ne sont pas de vrais avantages à mon avis:

  • L'ajout d'échelle à des entiers n'a de sens que dans très peu de cas (dans la plupart des cas où l'échelle fait une différence, elle pourrait également être ajoutée au préalable)
  • SQL Server voit chaque combinaison précision / échelle comme un type de données différent, donc le type de données n'est pas laissé seul lors de l'augmentation de la précision ou de l'échelle.

Cela me fait me demander: quel est l'avantage supplémentaire d'un DECIMAL(5,0)type de données pour les entiers?

vstrien
la source
1
Un avantage peut être la limite à cinq chiffres. Mais je me demande combien d'espace de stockage pouvez-vous épargner avec un tel changement.
dezso
3
IMO, si vous avez juste besoin de vous assurer que les valeurs des colonnes se situent dans une plage, utilisez une contrainte de vérification. Je pense que la seule considération ici serait s'il y a la possibilité que cette colonne nécessite des valeurs fractionnaires à l'avenir.
Jon Seigel
3
S'ils s'inquiètent de l'espace de stockage, ils sont mieux adaptés à la compression que cela. Il n'y a aucun avantage tangible à utiliser décimal (x, 0) au lieu de int / bigint.
Robert L Davis
7
Une autre différence entre decimal(x,0)et un type entier se manifeste dans la division arithmétique. Si vous divisez un int par un int, vous obtenez un int. Si vous divisez une décimale (x, 0) par un entier, vous obtenez une décimale (x + 6,6).
Andriy M
@AndriyM, je pense que c'est le plus grand avantage. Reformulez-le dans une réponse au lieu d'un commentaire et je le marquerai comme réponse.
vstrien

Réponses:

8

Je suis d'accord qu'il n'y a pas de réels avantages en termes d' espace de stockage tant que vous comparez DECIMAL (9, 0) vs INT ou DECIMAL (18, 0) vs BIGINT. (Dans un seul octet.)

En termes de traitement, comme @Andriy le dit, le DECIMAL se divisera naturellement en un type qui ne perdra pas la partie fractionnaire, si cela est important pour vous.

D'un autre côté, travailler avec des types INT natifs est beaucoup plus rapide d'un point de vue numérique si vous effectuez un grand nombre de SUM () ou de comparaisons (telles que la recherche sur les valeurs) car ils sont pipelinés plus efficacement par le CPU. Une comparaison int est deux opcodes d'assemblage (MOV, CMP) mais toute comparaison décimale sera beaucoup, beaucoup plus.

Chris Chubb
la source
Votre réponse est logique, mais un processeur n'a aucune connaissance des types de données. Ainsi, un type de données de 4 octets est comparé aussi rapidement qu'un autre type de données de 4 octets. Pouvez-vous montrer (avec un test de performance reproductible, par exemple) qu'il y a un impact sur les performances en utilisant DECIMAL(9, 0)au lieu d'un INT?
vstrien
2
Je pensais que je pouvais, mais je dois admettre que mes tests ne sont pas concluants. Peut-être que SQL fait une optimisation pour réduire le problème aux mathématiques entières. Mon banc d'essai: `--Int comparaison SET @StartTime = SYSDATETIME () WHILE (@CounterINT <@SizeINT) SET @CounterINT = @CounterINT + 1 PRINT 'INT pris' + CONVERT (VARCHAR (20), DATEDIFF (milliseconde, @StartTime , SYSDATETIME ())) + 'millisecondes' --Decimal SET @StartTime = SYSDATETIME () WHILE (@CounterDEC <@SizeDEC) SET @CounterDEC = @CounterDEC + 1 PRINT 'DEC a pris' + CONVERT (VARCHAR (20), DATEDIFF (milliseconde, @StartTime, SYSDATETIME ())) + 'millisecondes' '
Chris Chubb
Je pense que SQL Server y optimise quelque chose. Malgré l'optimisation, cela DECIMALprend généralement un peu plus de temps (au moins sur mon système de développement). En 10 tests, environ 51 ms DEC contre 46 ms INT.
vstrien
2

Il semble qu'il n'y ait aucun avantage en termes d'espace de stockage.

Si votre client craint que vos valeurs soient supérieures à 2 ^ 32-1 (un entier de valeur positive maximale peut stocker), vous devriez envisager de passer à BigInt - avec 64 bits ( 8 octets) .

AlexTheDeveloper
la source