Tipos de Datos en MySQL
Elegir correctamente los tipos de datos en una base de datos afecta el rendimiento, la integridad y la escalabilidad del sistema.
¿Por qué importa el tipo de dato?
- Elegir el tipo correcto ahorra espacio en disco y tiempo en consultas
- Impone restricciones útiles (ej: no meter texto donde va un número)
- Aumenta la claridad del modelo de datos
- Previene errores extraños al ordenar, filtrar o calcular
Consideraciones clave antes de elegir
-
¿Qué representa el dato?
¿Texto, número, valor booleano, fecha? -
¿Cuánto varía su longitud?
¿Es fijo (como un código postal) o variable (como un comentario)? -
¿Lo vas a comparar, ordenar o agrupar?
Hay collations más o menos adecuadas para cada idioma. -
¿Cuánto precisión necesitas?
Por ejemplo: dinero = mas exactitud (DECIMAL
), estadísticas = mejor rendimiento (FLOAT
).
Tipos de datos numéricos
Tipo | Tamaño típico | Rango (con signo) | Comentario |
---|---|---|---|
TINYINT |
1 byte | -128 a 127 | Muy compacto |
SMALLINT |
2 bytes | -32,768 a 32,767 | |
INT |
4 bytes | -2 mil millones | Ideal para IDs |
BIGINT |
8 bytes | ±9 cuatrillones | Para facturas o totales grandes |
DECIMAL(10,2) |
depende | Precisión fija para decimales | Usado en dinero |
FLOAT , DOUBLE |
4-8 bytes | Más rápido, menos preciso | Evitar en cálculos críticos |
DECIMAL
guarda dígito a dígito → exactitud perfectaFLOAT
yDOUBLE
usan coma flotante → pueden tener error por redondeo
Tipos de cadenas (texto)
Tipo | Tamaño | Comentario |
---|---|---|
CHAR(n) |
fijo | Rellena con espacios si es más corto |
VARCHAR(n) |
variable | Longitud real + 1 o 2 bytes extra |
TEXT |
hasta 65 KB | No indexable completamente |
MEDIUMTEXT |
hasta 16 MB | Para posts largos, artículos |
LONGTEXT |
hasta 4 GB | Raramente necesario |
VARCHAR(255)
Aun siendo una opinión extendida, varchar no tiene un límite físico o lógico a 255 caracteres. Pero los índices compuestos y la codificación pueden imponer restricciones.
Tipos de fecha y hora
Tipo | Formato | Comentario |
---|---|---|
DATE |
YYYY-MM-DD |
Solo fecha |
DATETIME |
YYYY-MM-DD HH:MM:SS |
Sin zona horaria |
TIMESTAMP |
Igual que DATETIME |
Ajusta según huso horario del servidor |
TIME |
HH:MM:SS |
Duraciones o intervalos |
YEAR |
YYYY |
Solo año |
TIMESTAMP
tiene rango limitado (1970-2038) mientras DATETIME
va de 1000-9999
Otros tipos
ENUM('A','B')
: valor limitado a una listaSET('x','y','z')
: múltiple elección sobre un conjuntoBLOB
,MEDIUMBLOB
: datos binarios (fotos, adjuntos)BOOLEAN
: sinónimo deTINYINT(1)
en realidadBIT
permite almacenar n bits exactos en una columna. No es sinónimo deboolean
ENUM
es cómodo, pero costoso de migrar si cambian las opciones. A veces es mejor tener una tabla auxiliar.
Como limitar el contenido de una entrada
El valor en INT(4)
no restringe el número de cifras. Solo afecta cómo se presenta si se usa con ZEROFILL
:
id INT(4) ZEROFILL → mostrará 0042 en vez de 42
Números
-
Usar el tipo adecuado (
TINYINT
,SMALLINT
, etc.) para limitar el rango natural. -
Agregar restricciones con
CHECK
:
edad TINYINT UNSIGNED CHECK (edad <= 120)
Texto
-
Controlar longitud con
VARCHAR(n)
oCHAR(n)
-
Validar formato con expresiones regulares o
CHECK
:
codigo_postal CHAR(5) CHECK (codigo_postal REGEXP '^[0-9]{5}$')
Casos comunes
Campo | Tipo de dato recomendado | Validación adicional |
---|---|---|
DNI | CHAR(9) |
CHECK (CHAR_LENGTH(dni) = 9) |
Código Postal | CHAR(5) o CHAR(6) |
REGEXP '^[0-9]{5,6}$' si necesario |
Teléfono | VARCHAR(15) |
CHECK (telefono REGEXP '^\\+?[0-9]{9,15}$') |
Contraseña | VARCHAR(72) |
(si usas bcrypt) |
Edad | TINYINT UNSIGNED |
CHECK (edad BETWEEN 0 AND 120) |
Precio | DECIMAL(10,2) |
Para precisión con 2 decimales |
Consejos
UNSIGNED
: elimina valores negativos: rango positivo más amplioZEROFILL
: completa números con ceros a la izquierda (00042
)AUTO_INCREMENT
: para claves primarias numéricas
Ejemplo: tabla de usuarios
CREATE TABLE usuarios (
id INT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
email VARCHAR(254) NOT NULL,
edad TINYINT UNSIGNED CHECK (edad BETWEEN 13 AND 120),
salario DECIMAL(10,2),
fecha_registro TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);