Cuando diseñas una tabla en tu base de datos, ¿cómo decides qué tipo numérico asignarle a cada columna?
«Para enteros, INT y listo.» «Mejor prevenir que curar: ponle BIGINT.» «Tiene decimales, así que FLOAT.» Si estas frases te resultan familiares, no eres el único. Pero tomar decisiones por defecto así puede provocar problemas de rendimiento, desperdicio de almacenamiento e incluso errores críticos en cálculos financieros a medio plazo.
Piensa en esto: cambiar INT por BIGINT en una sola columna de una tabla con 100 millones de filas añade aproximadamente 400 MB de almacenamiento. Si sumamos dos índices, la diferencia supera 1 GB. En el extremo opuesto, elegir INT para una tabla de logs de alto volumen que crece millones de filas al día puede provocar un desbordamiento en pocos años, deteniendo tu aplicación por completo.
Y luego está FLOAT. La mayoría de los desarrolladores saben que 0.1 + 0.2 da como resultado 0.30000000000000004 en lugar de 0.3. Sin embargo, las columnas FLOAT siguen apareciendo en tablas de pagos en producción, acumulando silenciosamente errores de redondeo hasta que los informes de facturación mensual dejan de cuadrar.
Este artículo es una guía completa de los cuatro tipos numéricos más importantes en SQL — INT, BIGINT, DECIMAL y FLOAT — cubriendo sus diferencias, ventajas y desventajas, y reglas prácticas de decisión que puedes aplicar de inmediato.
El diseño de base de datos es la base de cualquier sistema de software. Para fundamentos de diseño orientado a objetos, consulta la Guía de Principios SOLID. Si necesitas ayuda para elegir un lenguaje de programación, echa un vistazo a la Guía Comparativa de Lenguajes de Programación.
Tipos numéricos en SQL de un vistazo
Empecemos con la visión general. La siguiente tabla resume todos los tipos numéricos principales. En las secciones siguientes profundizaremos en cada uno.
| Tipo | Tamaño | Rango (aprox.) | Precisión | Uso típico |
|---|---|---|---|---|
| TINYINT | 1 byte | 0 – 255 / -128 – 127 | Exacta | Flags, códigos de estado |
| SMALLINT | 2 bytes | 0 – 65.535 | Exacta | Contadores pequeños |
| INT | 4 bytes | ~2.100 millones / ~4.200 millones | Exacta | IDs, cantidades, contadores |
| BIGINT | 8 bytes | ~9,2 trillones | Exacta | IDs de log, PKs a gran escala |
| DECIMAL(M,D) | Variable | M dígitos (D decimales) | Exacta | Dinero, tasas de impuestos, ratios |
| FLOAT | 4 bytes | ±3,4 × 10³⁸ | Aproximada | Temperatura, datos de sensores |
| DOUBLE | 8 bytes | ±1,7 × 10³⁰⁸ | Aproximada | Coordenadas GPS, estadísticas |
Los cuatro tipos que más importan en el día a día son INT, BIGINT, DECIMAL y FLOAT. Domina estos cuatro y podrás resolver la gran mayoría de diseños de bases de datos del mundo real sin problemas.
Tipos enteros (familia INT) — El punto de partida por defecto
Los enteros son el tipo numérico más rápido, más eficiente en almacenamiento y libre de errores en SQL. Ganan en velocidad de cálculo, eficiencia de índices y huella en disco. Si una columna no necesita decimales, un tipo entero es siempre la elección correcta.
MySQL ofrece cinco tamaños de enteros:
| Tipo | Tamaño | Rango SIGNED | Rango UNSIGNED |
|---|---|---|---|
| TINYINT | 1 byte | -128 a 127 | 0 a 255 |
| SMALLINT | 2 bytes | -32.768 a 32.767 | 0 a 65.535 |
| MEDIUMINT | 3 bytes | -8.388.608 a 8.388.607 | 0 a 16.777.215 |
| INT | 4 bytes | -2.147.483.648 a 2.147.483.647 | 0 a 4.294.967.295 |
| BIGINT | 8 bytes | -9,2 trillones a 9,2 trillones | 0 a ~18,4 trillones |
La regla de oro: si puedes representarlo como un entero, usa un tipo entero. Por ejemplo, si tu sistema maneja precios en céntimos de euro, price_cents INT funciona perfectamente. INT llega hasta unos 2.100 millones, lo que significa que puede manejar cantidades de hasta 21 millones de euros en céntimos — más que suficiente para la mayoría de productos de e-commerce.
Casos de uso habituales para enteros:
- IDs (claves primarias): user_id, product_id, order_id
- Cantidades: stock_quantity, cart_count
- Contadores: login_count, view_count, retry_count
- Códigos de estado: order_status (0 = pendiente, 1 = pagado, 2 = enviado …)
- Flags booleanos: is_active, is_deleted (TINYINT con 0/1)
No hay ninguna razón para usar DECIMAL o FLOAT en estos casos. Los enteros son la opción más rápida y segura.
INT vs. BIGINT — ¿«Mejor prevenir que curar» es realmente seguro?
El dilema más frecuente al elegir un tipo entero es INT frente a BIGINT. La respuesta corta: INT es suficiente para la inmensa mayoría de los casos de uso. La respuesta larga revela por qué ascender todo a BIGINT a ciegas es un antipatrón costoso.
Primero, pongamos las cifras en perspectiva. INT UNSIGNED llega hasta unos 4.200 millones. La población de España es de unos 47 millones — apenas un 1,1 % de la capacidad de INT. Un servicio web con 1 millón de usuarios podría almacenar 4.000 registros de log por usuario y seguir dentro del rango de INT. Para IDs de usuario, de producto y de pedido, INT es casi siempre más que suficiente.
Entonces, ¿cuándo se hace necesario BIGINT?
- Logs de acceso: Un sitio con 100 millones de páginas vistas al mes acumula 1.200 millones de filas al año. En 3–4 años, el techo de INT está a la vista
- Datos de sensores IoT: 10.000 dispositivos enviando datos cada segundo generan aproximadamente 315.000 millones de filas al año — muy por encima del rango de INT
- IDs distribuidos (Snowflake, etc.): Codifican un timestamp, un ID de worker y un número de secuencia en un solo valor que puede ser extremadamente grande
- IDs de transacciones: Un sistema de pagos que procesa 1 millón de transacciones al día alcanza 3.650 millones en 10 años — peligrosamente cerca del límite de INT
Ahora cuantifiquemos el coste de «usar BIGINT para todo»:
| Escenario | INT (4 bytes) | BIGINT (8 bytes) | Diferencia |
|---|---|---|---|
| 100M filas × 1 columna | 381 MB | 762 MB | +381 MB |
| 100M filas × 1 col + 2 índices | 1,14 GB | 2,29 GB | +1,14 GB |
| Memoria para JOIN (estimada) | Línea base | ~1,5–2× | Menor eficiencia de caché |
En una tabla de 100 millones de filas, cambiar una sola columna más dos índices de INT a BIGINT desperdicia más de 1,1 GB. Multiplica eso por varias columnas y varias tablas, y el total puede alcanzar decenas de gigabytes — todo lo cual incrementa la E/S de disco, reduce la eficiencia del buffer pool y ralentiza las consultas.
Una guía práctica de decisión:
| Propósito de la columna | Tipo recomendado | Razonamiento |
|---|---|---|
| ID de usuario | INT UNSIGNED | Muy pocos servicios superan los 4.200 millones de usuarios |
| ID de producto | INT UNSIGNED | Mismo razonamiento |
| ID de pedido | INT UNSIGNED o BIGINT | Depende del volumen y la vida útil |
| ID de log de acceso | BIGINT | Miles de millones de filas esperadas al año |
| Snowflake / UUID numérico | BIGINT | Los valores son inherentemente grandes |
No bases tu elección solo en el número actual de filas. Lo que importa es la tasa de crecimiento durante toda la vida operativa del sistema. Estima las inserciones anuales, proyéctalas a 10 años y comprueba si INT UNSIGNED (4.200 millones) aguantará. Si no, empieza con BIGINT desde el primer día.
UNSIGNED — El doble de rango gratis
En MySQL y MariaDB, añadir UNSIGNED a una columna entera elimina el rango negativo y duplica el rango positivo sin coste adicional de almacenamiento. Un INT normal abarca desde aproximadamente -2.100 millones hasta +2.100 millones; INT UNSIGNED abarca 0 a 4.200 millones — los mismos 4 bytes.
Columnas como IDs, cantidades y contadores nunca son negativas. No hay razón para no usar UNSIGNED en ellas.
CREATE TABLE users (n id INT UNSIGNED AUTO_INCREMENT PRIMARY KEY,n age TINYINT UNSIGNED, u002du002d 0u0026lt;=255 es suficienten login_count INT UNSIGNED DEFAULT 0,n point INT UNSIGNED DEFAULT 0n);
La resta entre dos columnas UNSIGNED puede provocar un underflow. En MySQL, SELECT a - b donde a < b produce un valor enorme (o un error) porque el resultado «da la vuelta». Si la resta es posible, usa CAST(a AS SIGNED) - CAST(b AS SIGNED) o considera mantener la columna como SIGNED.
Nota: PostgreSQL no soporta UNSIGNED. La solución habitual es usar una restricción CHECK (CHECK (id >= 0)) para forzar valores no negativos a nivel de aplicación.
DECIMAL (NUMERIC) — La única opción correcta para dinero
DECIMAL almacena números como valores exactos en base 10. A diferencia de FLOAT, no convierte internamente a binario, por lo que 0,1 se almacena exactamente como 0,1. Para cualquier columna donde importe hasta la última fracción de céntimo — precios, facturas, impuestos, saldos de cuentas — DECIMAL es el único tipo aceptable.
¿Por qué no FLOAT? Veamos el problema en acción:
u002du002d Qué pasa con FLOATnSELECT CAST(0.1 AS FLOAT) + CAST(0.2 AS FLOAT);nu002du002d Resultado: 0.30000001192092896 (no es 0.3)nnu002du002d DECIMAL lo calcula correctamentenSELECT CAST(0.1 AS DECIMAL(10,2)) + CAST(0.2 AS DECIMAL(10,2));nu002du002d Resultado: 0.30 (exactamente 0.30)
¿Cómo importa este pequeño error en la práctica? Imagina una tienda online que vende un artículo de 11,99 € y procesa 50.000 pedidos al mes:
- Con FLOAT: Cada fila puede arrastrar un error tan pequeño como +0,000001, pero a lo largo de 50.000 filas y múltiples cálculos de IVA, las discrepancias de redondeo se acumulan. Multiplica por cientos de SKUs durante un año, y el balance se desvía en euros — suficiente para desencadenar una investigación de auditoría
- Con DECIMAL: Cero desviación. Cada agregación cuadra al céntimo, siempre
«Es solo una millonésima de euro.» Cierto — pero en contabilidad, si los libros no cuadran al céntimo, alguien tiene que explicar por qué. «Usamos el tipo de columna equivocado» no es una respuesta que ningún auditor vaya a aceptar.
DECIMAL se declara como DECIMAL(M, D) donde M es el total de dígitos y D los decimales:
u002du002d DECIMAL(10,2): 10 dígitos en total, 2 decimalesnu002du002d Valor máximo: 99.999.999,99nnCREATE TABLE orders (n id INT UNSIGNED AUTO_INCREMENT PRIMARY KEY,n subtotal DECIMAL(10,2) NOT NULL, u002du002d Importe antes de impuestosn tax_rate DECIMAL(5,4) NOT NULL, u002du002d ej. 0.2100 (21% IVA)n tax_amount DECIMAL(10,2) NOT NULL, u002du002d Impuestosn total DECIMAL(10,2) NOT NULL u002du002d Total finaln);
DECIMAL y NUMERIC son sinónimos en el estándar SQL. MySQL, PostgreSQL y SQL Server los tratan de forma idéntica. Elige uno y sé consistente en todo tu código.
Dimensionar DECIMAL — Por qué DECIMAL(18,10) casi siempre es excesivo
Otro error frecuente es especificar una precisión excesiva: DECIMAL(18,10) o incluso DECIMAL(30,15) «por si acaso». Esto desperdicia almacenamiento y ralentiza las agregaciones.
El tamaño de almacenamiento de DECIMAL es proporcional a su número de dígitos. En MySQL, cada 9 dígitos consumen 4 bytes, con bytes extra para los dígitos restantes:
| Tipo | Almacenamiento (MySQL) | Ejemplo de uso |
|---|---|---|
| DECIMAL(5,2) | 3 bytes | Porcentajes (hasta 99,99 %) |
| DECIMAL(10,2) | 5 bytes | Precios (hasta 99.999.999,99 €) |
| DECIMAL(12,4) | 6 bytes | Tipos de cambio (ej. 1,3456) |
| DECIMAL(18,10) | 9 bytes | Excesivo para la mayoría de aplicaciones |
El enfoque correcto es partir del valor máximo e ir hacia atrás:
- Precios de e-commerce: Si el precio más alto es de unos pocos millones de euros, DECIMAL(10,2) cubre hasta 99.999.999,99 €
- Tasas de IVA: En España el tipo general es del 21 %. DECIMAL(5,4) admite hasta 99,9999 %
- Porcentajes de descuento: 0–100 % cabe en DECIMAL(5,2)
- Tipos de cambio: EUR/USD a 1,0845 — DECIMAL(12,4) ofrece margen de sobra
- Criptomonedas: La unidad más pequeña de Ethereum (wei = 10⁻¹⁸ ETH) realmente necesita DECIMAL(36,18) — un caso raro donde la precisión extrema está justificada
Usar DECIMAL(18,10) para una columna de precios en retail es como imprimir una nota personal en un pliego de papel A0. Ajusta la precisión al tamaño justo y ahorrarás almacenamiento y acelerarás las consultas.
FLOAT / DOUBLE — Velocidad a costa de la exactitud
FLOAT y DOUBLE son tipos de punto flotante que representan decimales usando el formato binario IEEE 754. Esto les da una gran ventaja y una limitación inherente.
La ventaja es clara: unos fijos 4 bytes (FLOAT) u 8 bytes (DOUBLE) pueden representar un rango enorme de valores. Solo FLOAT cubre ±3,4 × 10³⁸, y el hardware de punto flotante de la CPU realiza la aritmética extremadamente rápido.
La limitación es que almacenan aproximaciones, no valores exactos. El decimal 0,1 se convierte en el binario infinito periódico 0,000110011001100… que debe redondearse para caber en un número finito de bits. Esta es la causa raíz del famoso problema «0,1 + 0,2 ≠ 0,3».
FLOAT es la elección adecuada cuando pequeños errores de redondeo no afectan al resultado:
- Lecturas de temperatura: Un sensor industrial reporta 23,45 °C con una precisión intrínseca de ±0,1 °C. Un error de almacenamiento de ±0,0001 °C carece de importancia
- Coordenadas GPS: Seis decimales en latitud/longitud corresponden a ~11 cm de precisión. DOUBLE mantiene hasta 15 dígitos significativos — precisión submilimétrica que supera con creces cualquier necesidad real
- Features de machine learning: Los modelos de ML tienen millones o miles de millones de parámetros; un redondeo microscópico en un peso individual tiene un impacto despreciable en la precisión global
- Simulaciones físicas: La dinámica de fluidos y el análisis estructural dependen de la velocidad de FLOAT, con el error controlado a nivel de algoritmo
- Agregados estadísticos: Medias, desviaciones típicas y correlaciones se calculan a partir de datos que ya contienen ruido estadístico
La diferencia entre FLOAT y DOUBLE se reduce a precisión y almacenamiento:
| Tipo | Tamaño | Dígitos significativos | Cuándo elegirlo |
|---|---|---|---|
| FLOAT | 4 bytes | ~7 | Almacenamiento limitado, datos de sensores |
| DOUBLE | 8 bytes | ~15 | Alta precisión necesaria: GPS, cálculo científico |
Guardar coordenadas GPS como FLOAT ofrece solo ~7 dígitos significativos — aproximadamente 11 m de precisión. Para una aplicación de mapas, DOUBLE (~15 dígitos, submilimétrico) es la opción clara. Por el contrario, guardar lecturas de sensores de temperatura como DOUBLE no tiene sentido cuando el propio sensor solo tiene una precisión de ±0,5 °C — FLOAT es más que suficiente.
FLOAT vs. DECIMAL — Guía rápida de decisión
En la práctica, necesitas tomar esta decisión de forma rápida y segura. Aquí tienes una tabla de referencia:
| Caso de uso | DECIMAL | FLOAT / DOUBLE |
|---|---|---|
| Precios, facturas, facturación | ✓ | ✗ (nunca) |
| Tasas de impuestos, descuentos | ✓ | ✗ |
| Puntos de fidelización / millas | ✓ (si son fraccionarios) | ✗ |
| Peso de inventario (kg, lb) | ✓ | △ |
| Temperatura / humedad | △ | ✓ |
| Coordenadas GPS | △ | ✓ (DOUBLE) |
| Datos de sensores | △ | ✓ |
| Features de ML / scores | ✗ | ✓ |
| Valores estadísticos (media, etc.) | △ | ✓ |
La regla general cabe en tres líneas:
- ¿Hay dinero de por medio? → DECIMAL
- ¿Medición o ciencia? → FLOAT / DOUBLE
- ¿No estás seguro? → DECIMAL (mejor pecar de precavido)
Memoriza estas tres reglas y rara vez te equivocarás.
Cinco errores de diseño habituales
Los errores de tipo numérico suelen ser invisibles durante el desarrollo y solo afloran en producción. Estos son los cinco más frecuentes.
Error 1: Poner BIGINT en todas las columnas
La mentalidad de «más grande es más seguro» lleva a los equipos a poner BIGINT por defecto en cada columna entera. Como hemos visto, esto puede desperdiciar más de 1 GB por cada 100 millones de filas en una sola columna más índices. En 10 tablas con 3 columnas BIGINT cada una, eso supone unos 12 GB de almacenamiento desperdiciado — impactando directamente en los costes de hosting en la nube y en la eficiencia del buffer pool.
Error 2: Usar FLOAT para dinero
Este es el error más peligroso de la lista. A menudo pasa todos los tests unitarios porque los errores de redondeo son invisibles a pequeña escala. El problema aparece en producción cuando el volumen de transacciones crece: «La facturación mensual no coincide con los depósitos bancarios reales.» El análisis de causa raíz lleva días, y corregir retroactivamente datos financieros almacenados con FLOAT es extremadamente difícil.
Error 3: Sobredimensionar la precisión de DECIMAL
Definir DECIMAL(30,15) «por si acaso» desperdicia almacenamiento y ralentiza las consultas de agregación. Fuera de las criptomonedas (donde 18 decimales son realmente necesarios), muy pocos dominios de negocio requieren más de 4 decimales.
Error 4: No prever el desbordamiento de INT
Una tabla puede empezar con solo unos cientos de inserciones al día, pero el crecimiento puede ser exponencial. INT SIGNED llega hasta ~2.100 millones. Con AUTO_INCREMENT a 50.000 inserciones/día, eso son 117 años de margen — pero los volcados de datos de prueba, los huecos en los IDs y el crecimiento inesperado pueden consumir ese margen más rápido de lo esperado. Monitoriza tus marcas de agua de AUTO_INCREMENT regularmente.
Error 5: Tipos distintos en los JOIN
Si orders.user_id es INT pero users.id es BIGINT, cada JOIN dispara una conversión implícita de tipos. En MySQL, esto puede impedir que el optimizador use los índices, convirtiendo una consulta de milisegundos en un escaneo completo de tabla de varios segundos. Asegúrate siempre de que las columnas usadas en JOINs compartan exactamente el mismo tipo.
Tipos recomendados por caso de uso
Usa esta tabla de referencia rápida cuando diseñes nuevas tablas:
| Propósito de la columna | Tipo recomendado | Notas |
|---|---|---|
| ID de usuario | INT UNSIGNED | 4.200 millones son suficientes |
| ID de producto | INT UNSIGNED | Mismo razonamiento |
| ID de log / evento | BIGINT UNSIGNED | Miles de millones de filas al año |
| ID Snowflake | BIGINT | Valores inherentemente grandes |
| Precio de producto | DECIMAL(10,2) | Máx. 99.999.999,99 € |
| Tasa de IVA | DECIMAL(5,4) | ej. 0.2100 (21 %) |
| Tasa de descuento | DECIMAL(5,2) | ej. 15,50 % |
| Tipo de cambio | DECIMAL(12,4) | ej. 1,0845 |
| Cantidad en stock (entera) | INT UNSIGNED | No necesita decimales |
| Peso (kg / lb) | DECIMAL(8,3) | ej. 12345,678 |
| Temperatura | FLOAT | La precisión del sensor es suficiente |
| GPS lat / lng | DOUBLE | Se requiere alta precisión |
| Feature de ML | FLOAT | Velocidad por encima de precisión |
| Puntos (enteros) | INT UNSIGNED | Sin fracciones |
| Puntos (fraccionarios) | DECIMAL(10,2) | Millas de aerolínea, etc. |
| Posición en ranking | INT UNSIGNED | Los rankings no son negativos |
| Flag booleano (0/1) | TINYINT UNSIGNED | Lo que MySQL usa internamente para BOOLEAN |
| Código de estado | TINYINT o SMALLINT | Dimensiona según el rango de valores |
Compartir una tabla como esta en tu equipo elimina la mayoría de debates sobre tipos durante las revisiones de código.
CREATE TABLE — Ejemplos del mundo real
Por último, aquí tienes tres definiciones de tablas listas para producción. Fíjate en cómo cada columna usa el tipo más pequeño adecuado.
Ejemplo 1: Productos de e-commerce
CREATE TABLE products (n id INT UNSIGNED AUTO_INCREMENT PRIMARY KEY,n name VARCHAR(255) NOT NULL,n price DECIMAL(10,2) NOT NULL DEFAULT 0.00, u002du002d Dinero = DECIMALn tax_rate DECIMAL(5,4) NOT NULL DEFAULT 0.2100, u002du002d 21% IVA = 0.2100n stock INT UNSIGNED NOT NULL DEFAULT 0, u002du002d Cantidad enteran weight_kg DECIMAL(8,3), u002du002d Peso para envíon rating FLOAT, u002du002d Valoración median is_active TINYINT UNSIGNED NOT NULL DEFAULT 1, u002du002d Flag booleanon created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMPn) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
Ejemplo 2: Logs de acceso
CREATE TABLE access_logs (n id BIGINT UNSIGNED AUTO_INCREMENT PRIMARY KEY, u002du002d Alto volumenn user_id INT UNSIGNED, u002du002d Coincide con el tipo de users.idn status_code SMALLINT UNSIGNED NOT NULL, u002du002d HTTP 200, 404, 500...n response_ms INT UNSIGNED, u002du002d Tiempo de respuesta en msn created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,n INDEX idx_user (user_id),n INDEX idx_created (created_at)n) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
Ejemplo 3: Lecturas de sensores IoT
CREATE TABLE sensor_readings (n id BIGINT UNSIGNED AUTO_INCREMENT PRIMARY KEY,n device_id INT UNSIGNED NOT NULL,n temperature FLOAT, u002du002d La precisión del sensor es suficienten humidity FLOAT, u002du002d Ídemn latitude DOUBLE, u002du002d GPS necesita alta precisiónn longitude DOUBLE, u002du002d Ídemn battery_pct TINYINT UNSIGNED, u002du002d Batería 0-100%n recorded_at DATETIME(3) NOT NULL, u002du002d Precisión de milisegundosn INDEX idx_device_time (device_id, recorded_at)n) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
Las tres tablas comparten un rasgo común: cada columna está definida con el tipo más pequeño que cumple su propósito. Los IDs escalan con INT o BIGINT según la necesidad, el dinero usa DECIMAL, las mediciones usan FLOAT/DOUBLE, y los flags usan TINYINT. Así es como luce un esquema bien diseñado.
Resumen — Elegir el tipo es ingeniería de rendimiento
Elegir un tipo numérico en SQL no es solo una decisión de formato. Afecta a la eficiencia de almacenamiento, rendimiento de índices, velocidad de consultas, exactitud de los datos y escalabilidad futura — todo a la vez.
Lo esencial en cuatro líneas:
- Si cabe en un entero, usa un tipo entero (el más rápido, el más pequeño, cero errores)
- INT para la mayoría de columnas, BIGINT para logs de alto volumen (el almacenamiento se duplica)
- DECIMAL para dinero — sin excepciones (los errores de FLOAT son devastadores en finanzas)
- FLOAT / DOUBLE para ciencia y mediciones (velocidad y rango donde la aproximación es aceptable)
Sobre todo, el principio rector es: elige el tipo más pequeño que cumpla con tus requisitos. Los tipos sobredimensionados desperdician almacenamiento, reducen la eficiencia de caché y ralentizan las consultas. Los tipos infradimensionados arriesgan el desbordamiento. Acertar significa estimar la naturaleza de tus datos (entero vs. decimal), el rango de valores, la tolerancia al error y la tasa de crecimiento durante la vida útil del sistema.
El diseño de tipos numéricos no es un trabajo glamuroso, pero hacerlo bien desde el primer día te ahorra degradación de rendimiento, inflado de almacenamiento e incidencias en producción a largo plazo. Cada vez que escribas un CREATE TABLE, pregúntate: «¿Es este tipo realmente el adecuado?» Solo ese hábito elevará la calidad de tu diseño de base de datos.
Preguntas frecuentes
P. ¿En qué debería pensar primero cuando no tengo claro qué tipo usar?
R. Empieza preguntándote: «¿Se puede representar este valor como un entero?» Si la respuesta es sí, ve con un tipo INT. Después pregúntate: «¿Tiene que ver con dinero?» Si es así, DECIMAL es la única respuesta. Todo lo demás con decimales — temperaturas, coordenadas, puntuaciones — apunta a FLOAT o DOUBLE. Sigue esta secuencia y el 95 % de las decisiones serán instantáneas.
P. ¿Lo complicado que es migrar de INT a BIGINT después?
R. El ALTER TABLE ... MODIFY COLUMN de MySQL puede cambiar el tipo, pero en tablas grandes bloquea la tabla durante minutos o incluso horas. Herramientas como pt-online-schema-change o gh-ost realizan la migración con prácticamente cero downtime, pero aun así requieren una planificación cuidadosa. Acertar con el tipo desde el principio siempre es más barato que corregirlo después.
P. PostgreSQL no soporta UNSIGNED — ¿qué hago?
R. Correcto. La solución estándar en PostgreSQL es usar una restricción CHECK (CHECK (id >= 0)) para forzar valores no negativos. Como el INT de PostgreSQL sigue llegando hasta ~2.100 millones, es suficiente para la mayoría de cargas de trabajo. Si realmente necesitas el rango de 4.200 millones, pasa a BIGINT.
P. ¿Cuánto afecta realmente el error de redondeo de FLOAT en la práctica?
R. FLOAT (4 bytes) tiene unos 7 dígitos significativos. Almacena 123456,789 en FLOAT y podrías recuperar 123456,7890625. Para datos de sensores o mediciones científicas — donde el propio instrumento tiene una precisión limitada — esto es irrelevante. Para cálculos financieros, significa facturas que se desvían un céntimo y totales mensuales que no cuadran. La regla es simple: nunca uses FLOAT para dinero.
P. ¿DECIMAL es realmente más lento que INT? ¿Cuánto?
R. En consultas con agregaciones pesadas (SUM, AVG sobre millones de filas), DECIMAL puede ser entre 1,2× y 2× más lento que INT. Para cargas de trabajo OLTP típicas — SELECTs e INSERTs individuales — la diferencia es despreciable. Algunos equipos almacenan precios como céntimos enteros (ej. 19,99 € → 1999) para ganar la velocidad de INT, pero esto se rompe en cuanto necesitas soporte multidivisa o cálculos por debajo del céntimo. Empezar con DECIMAL es la apuesta más segura a largo plazo.

Deja una respuesta