SQL Server Decimal (9, 0) vs INT

15

Uno de nuestros clientes usa para algunas columnas el tipo DECIMAL(18,0)de datos en su base de datos SQL Server 2008R2. Debido a que las columnas crecen bastante lentamente, recientemente propuso cambiar el tipo de datos DECIMAL(5,0)para recuperar algo de almacenamiento.

Según la biblioteca MSDN , el espacio de almacenamiento del DECIMAL(5,0)tipo de datos es, al igual que el DECIMAL(9,0)tipo de datos, 5 bytes. INTes 1 byte más pequeño, pero puede almacenar todo en el rango de -2 ^ 31 a 2 ^ 31 en lugar del -99,999 a 99,999 que DECIMAL(5,0)puede almacenar. Incluso el más grande DECIMALque cabe en 5 bytes ( DECIMAL(9,0)) puede almacenar solo enteros en el rango de -999,999,999 a 999,999,999 (que es menos de la mitad de las INTofertas de rango en 4 bytes).

Puedo pensar en dos "beneficios" de usar DECIMALmás de INT:

  • La capacidad de agregar escala después, sin usar más espacio de almacenamiento
  • La capacidad de escalar la precisión hasta 38 dígitos, sin alterar el tipo de datos

pero estos no son beneficios reales en mi opinión:

  • Agregar escala a enteros solo tiene sentido en muy pocos casos (en la mayoría de los casos en que la escala marca la diferencia, también se podría agregar de antemano)
  • SQL Server ve cada combinación de precisión / escala como un tipo de datos diferente, por lo que el tipo de datos no se queda solo al aumentar la precisión o la escala.

Esto me hace preguntarme: ¿cuál es el beneficio adicional de un DECIMAL(5,0)tipo de datos para enteros?

vstrien
fuente
1
Un beneficio puede ser el límite de cinco dígitos. Pero me pregunto cuánto espacio de almacenamiento puede ahorrar con tal cambio.
dezso
3
En mi opinión, si solo necesita asegurarse de que los valores de la columna se encuentren dentro de un rango, use una restricción de verificación. Creo que la única consideración aquí sería si existe la posibilidad de que esta columna requiera valores fraccionarios en el futuro.
Jon Seigel
3
Si les preocupa el espacio de almacenamiento, son más adecuados para usar compresión que esto. No hay un beneficio tangible al usar decimal (x, 0) en lugar de int / bigint.
Robert L Davis
77
Otra diferencia entre decimal(x,0)y un tipo entero se muestra en la división aritmética. Si divide un int por un int, obtiene un int. Si divide un decimal (x, 0) por un int, obtendrá un decimal (x + 6,6).
Andriy M
@AndriyM, creo que este es el mayor beneficio. Reformúlelo en una respuesta en lugar de un comentario y lo marcaré como respuesta.
vstrien

Respuestas:

8

Estoy de acuerdo en que no hay beneficios reales en términos de espacio de almacenamiento siempre que compare DECIMAL (9, 0) vs INT o DECIMAL (18, 0) vs BIGINT. (Dentro de un solo byte)

En términos de procesamiento, como @Andriy dice que DECIMAL se dividirá naturalmente en un tipo que no pierda la parte fraccional, si eso es importante para usted.

Por otro lado, trabajar con tipos INT nativos es mucho más rápido desde un punto de vista numérico si está haciendo muchas SUM () so comparaciones (como buscar los valores), ya que la CPU los canaliza de manera más eficiente. Una comparación int es dos códigos de operación de ensamblaje (MOV, CMP), pero cualquier comparación decimal será mucho, mucho más.

Chris Chubb
fuente
Su respuesta tiene sentido, pero un procesador no tiene ningún conocimiento de los tipos de datos. Entonces, un tipo de datos de 4 bytes se compara tan rápido como otro tipo de datos de 4 bytes. ¿Puede mostrar (con una prueba de rendimiento repetible, por ejemplo) que hay un éxito en el uso en DECIMAL(9, 0)lugar de un INT?
vstrien
2
Pensé que podía, pero admito que mis pruebas no son concluyentes. Quizás SQL está haciendo una optimización para reducir el problema a matemáticas enteras. Mi banco de pruebas: `--En comparación SET @StartTime = SYSDATETIME () WHILE (@CounterINT <@SizeINT) SET @CounterINT = @CounterINT + 1 PRINT 'INT tomó' + CONVERT (VARCHAR (20), DATEDIFF (milisegundos, @StartTime , SYSDATETIME ())) + 'milisegundos' --Decimal SET @StartTime = SYSDATETIME () WHILE (@CounterDEC <@SizeDEC) SET @CounterDEC = @CounterDEC + 1 PRINT 'DEC tomó' + CONVERT (VARCHAR (20), DATEDIFF (milisegundos, @StartTime, SYSDATETIME ())) + 'milisegundos' '
Chris Chubb
Creo que SQL Server optimiza algo allí de hecho. A pesar de que la optimización DECIMALtodavía tarda un poco más (al menos en mi sistema de desarrollo) En una serie de 10 pruebas alrededor de 51 ms DEC frente a 46 ms INT.
vstrien
2

Parece que no habrá beneficios en términos de espacio de almacenamiento.

Si a su cliente le preocupa que sus valores sean mayores que 2 ^ 32-1 (puede almacenar un número entero de valor positivo máximo), entonces debería considerar mudarse a BigInt , con 64 bits ( 8 bytes) .

AlexTheDeveloper
fuente