¿Cuándo usar TINYINT sobre INT?

91

En general, siempre uso Ints. Sin embargo, sé que, en teoría, esta no es la mejor práctica, ya que debe usar el tipo de datos más pequeño que se garantizará para almacenar los datos.

Por ejemplo, es mejor usarlo tinyintcuando sabe que los únicos datos que almacenará son 1, 0 o nulos (con una posibilidad muy pequeña de expandirlos a 2 o 3 más adelante).

Sin embargo, la única razón que sé para hacer esto es para fines de almacenamiento: usar 1 byte en una fila en lugar de 4 bytes.

¿Cuáles son los impactos del uso tinyint(o smallintincluso bigint) sobre solo int, aparte de ahorrar espacio en su disco duro?

Ricardo
fuente
2
Esta es una muy buena pregunta (+1). MySQL tiene SELECT ... PROCEDURE ANALYZE () que realmente recomienda los tipos de datos más pequeños que la tabla debería tener para el SELECT dado. Esa fue en parte la inspiración detrás de mi respuesta.
RolandoMySQLDBA
3
Buena pregunta, pero para precisar el rango tinyint es 0-255. El campo de bit es 0 o 1 (o NULL). El costo de almacenamiento para un tinyint es de 1 byte. Cada campo de 8 bits en una tabla costará 1 byte de almacenamiento. msdn.microsoft.com/en-us/library/ms187745.aspx y msdn.microsoft.com/en-us/library/ms177603.aspx
billinkc
@billinkc Derecha. Es por eso que mencioné la posibilidad de expandir la columna para incluir los valores 2 o 3. Si incluye 2 o 3, debe usar tinyint (en la escala más pequeña).
Richard
1
"Por ejemplo, es mejor usar tinyint cuando sabes que los únicos datos que almacenarás son 1, 0 o nulos (con muy pocas posibilidades de expandirlos a 2 o 3 más adelante)". Usaría un ENUM para tal cosa. Estos se almacenan como campos de bits, y como muchos otros han señalado aquí, los pequeños ahorros por registro se suman a los grandes ahorros en toda la base de datos, incluso más si la columna está indexada.
2
@ user6665 I'd use an ENUM for such a thing.No en SQL Server, no lo haría, ya que no tiene enumeraciones de ningún tipo.
underscore_d

Respuestas:

92

El espacio en disco es barato ... ¡ese no es el punto!

Deje de pensar en términos de espacio de almacenamiento, piense en la agrupación de almacenamiento intermedio y el ancho de banda de almacenamiento . En el extremo, la memoria caché de la CPU y el ancho de banda del bus de memoria . El artículo vinculado es parte de la serie que destaca los problemas con una selección de clave agrupada deficiente (INT vs GUID vs Secuencial GUID) pero destaca la diferencia que pueden hacer los bytes.

El mensaje principal es que el diseño es importante. La diferencia no se mostrará en una base de datos individual en un servidor adecuadamente especificado hasta que llegue al territorio VLDB, pero si puede guardar algunos bytes, ¿por qué no hacerlo?

Me recuerda el entorno descrito en una pregunta anterior . Más de 400 bases de datos, que varían en tamaño desde 50mb-50GB, por instancia de SQL. Eliminar algunos bytes por registro, por tabla, por base de datos en ese entorno podría marcar una diferencia significativa.

Mark Storey-Smith
fuente
29

Además de las otras respuestas ...

Las filas y las entradas de índice se almacenan en páginas de 8k. Por lo tanto, un millón de filas a 3 bytes por fila no son 3 MB en el disco: afecta el número de filas por página ("densidad de página").

Lo mismo se aplica a nvarchar a varchar, smalldatetime a datetime, int a tinyint, etc.

Editar, junio de 2013

http://sqlblog.com/blogs/joe_chang/archive/2013/06/16/load-test-manifesto.aspx

Este artículo establece

Los criterios importantes son la cardinalidad y la relación página a fila.

Entonces, la elección del tipo de datos sí importa

gbn
fuente
55
Buen punto. Un ejemplo absoluto del peor de los casos es una fila de 4028 bytes que consta de columnas de longitud completamente fija a las que desea agregar una columna. Agregar un smallint lo llevaría a 4030 (2 filas por página) pero un int lo empuja hacia el límite (1 fila por página, 4028 bytes desperdiciados por página).
Mark Storey-Smith
Una vez hice una prueba de rendimiento en int vs bigint. Ahorre 1 millón de registros, compare el tiempo y el almacenamiento, y recupérelos uno por uno, nuevamente midiendo el rendimiento. No vi grandes diferencias. Voy a hacer la misma prueba de rendimiento para int vs tinyint. Realmente creo que se puede descuidar para el 80% de las aplicaciones, lo que resulta en tipos de datos más consistentes y menores costos de mantenimiento.
Saeed Neamati
1
@SaeedNeamati Es posible que desee volver a leer el artículo de la respuesta de Mark (" ¿Alguna vez has escuchado ... terminemos esto? ¿Nos preocuparemos por el rendimiento más tarde? ... Escucho esto todo el tiempo ... ") y gbn está aquí . Creo que la conclusión es que cualquier elección ineficiente mostrará sus franjas en la escala correcta, y el intestino de OP no está mal.
ruffin
14

No es solo el almacenamiento de la mesa lo que se tiene en cuenta. Si usa índices donde la columna int es parte de una clave compuesta, naturalmente querrá que las páginas de índice estén lo más llenas posible, esto es el resultado de que las entradas de índice sean lo más pequeñas posible.

Definitivamente esperaría encontrar que examinar entradas de índice en páginas BTREE sería un poco más rápido con tipos de datos más pequeños. Sin embargo, cualquier VARCHAR involucrado en las entradas de índice compensaría (anularía) las ganancias de rendimiento al usar TINYINT sobre INT.

No obstante, si las entradas de índice tienen entradas compuestas y todas son números enteros, cuanto más pequeños sean los bytes, mejor y más rápido.

RolandoMySQLDBA
fuente
13

Todas las cosas se vuelven más complejas cuando las bases de datos se hacen más grandes:

  • las ventanas de mantenimiento deben ampliarse o reprogramarse
  • copias de seguridad (la copia de seguridad completa al final del día se convierte en un absurdo consumo de tiempo, por lo que necesita un diferencial o incluso registrar copias de seguridad y hacer la copia completa una vez a la semana, tal vez una vez al mes)
  • el mantenimiento del rendimiento se convierte en un factor de tiempo (la creación de un índice en una tabla de varias millones de filas no lleva un tiempo trivial de ejecución) y debe reprogramarse y empeora si la tabla es amplia ...
  • Y transmitir esa copia de seguridad de 100 Gb a través de la red no es lo que yo llamo pan comido, especialmente si la red (por alguna razón desconocida) es obstinada al dejar la conexión en la marca de 75 Gb ... (sucedió con una instalación en la que estaba trabajando estaba haciendo una copia de seguridad en una unidad asignada en la red - red) ...

¿Y qué tipos de datos tienen que ver con eso? TODO. El uso de tamaños de fila más grandes de lo necesario hace que las páginas de la base de datos se llenen antes de lo necesario o incluso desperdicia espacio si el tamaño de la fila es tal que no se puede registrar más de un registro en la página. El resultado es que se necesitan más páginas para escribir y leer, se usa más memoria RAM para almacenar en caché eso (los registros más grandes necesitan una memoria más grande). Y dado que sus tipos de datos se especifican más grandes de lo necesario desde el disco, sus índices sufrirán el mismo problema, especialmente si agrupa esa clave primaria compuesta de 2 columnas BIGINT ya que cualquier otro índice creado copiará esa clave primaria implícitamente en su definición.

Si sabe que algunas columnas en una tabla que tendrán millones de filas o incluso una pequeña tabla que se FK' a varios millones de filas que no necesita un entero de 4 bytes para almacenar sus datos, pero un byte de 2 suficiente - use SMALLINT . Si los valores en el rango 0-255 son suficientes, TINYINT . ¿Una bandera Sí / No? Hay BIT .

Fabricio Araujo
fuente
9

Si bien para tinyintvs inthay diferencias claras, como el espacio en disco, las divisiones de página y el tiempo de mantenimiento, no habría ninguno de estos para varchar.

Entonces, ¿por qué no declarar todos los campos de texto como varchar(4000), ya que de todos modos solo usará el espacio necesario? Aún más, se le garantizará que sus datos nunca se truncarán.

La respuesta es, por supuesto:

  1. Aclaración de sus intenciones (ya que nadie entenderá por qué un campo de nombre debe tener 4000 caracteres)
  2. Validación, ya que desea asegurarse de que nadie ingrese una biografía completa como nombre.

Estas mismas razones también se aplican tinyint.

Yoel Halb
fuente
3
Este es un hilo antiguo, pero la aclaración y la validación no son la única razón. Si tiene VARCHAR (4000) para algo que debería ser VARCHAR (20), el plan de consulta pensará que sus requisitos de memoria y CPU son muchos múltiplos de lo que deberían ser con respecto a esa columna. No me he tomado el tiempo para hacer esto, pero supongo que probablemente pueda ver esto mirando un plan de consulta para VARCHAR (20) y luego cambie a VARCHAR (4000) y verifique los costos estimados.
3
@GeorgeShouse Demostración de eso aquí
Martin Smith