Tipos de datos en MySQL: guía para elegir el adecuado
Resumen de los tipos de datos más usados en MySQL y cómo elegir entre números, textos, fechas y booleanos.
Actualizado el
El tipo de dato que asignas a cada columna en MySQL determina qué valores acepta, cuánto espacio ocupa, la precisión con la que se guardan y cómo se comportan la validación y la indexación.
Después de elegir cada tipo, puedes aplicarlo en una definición completa con CREATE TABLE en MySQL.
Elección rápida según el dato
| Dato | Elección habitual |
|---|---|
| ID | INT o BIGINT, según el rango |
| Importe | DECIMAL(M,D) |
| Texto corto | VARCHAR(N) |
| Texto largo | TEXT |
| Solo fecha | DATE |
| Fecha y hora civil | DATETIME |
| Instante con conversión de zona horaria | TIMESTAMP |
| Booleano | BOOLEAN / TINYINT(1) |
| Binario | VARBINARY o BLOB |
| Documento estructurado | JSON |
Tipos numéricos
| Tipo | Uso habitual |
|---|---|
TINYINT | Números pequeños, flags, valores tipo booleano. |
SMALLINT | Enteros pequeños. |
MEDIUMINT | Enteros medianos. |
INT | Enteros habituales: ids, contadores, cantidades. |
BIGINT | Enteros muy grandes. |
DECIMAL | Importes y valores que necesitan precisión exacta. |
FLOAT / DOUBLE | Decimales aproximados, mediciones o cálculos científicos. |
| Tipo | Almacenamiento | Con signo (SIGNED) | Sin signo (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.223.372.036.854.775.808 a 9.223.372.036.854.775.807 | 0 a 18.446.744.073.709.551.615 |
El rango SIGNED es el predeterminado; los bytes indican almacenamiento, no ancho de visualización.
DECIMAL guarda valores exactos y es adecuado para importes; FLOAT y DOUBLE son aproximados, así que no los uses para dinero.
precio DECIMAL(10, 2)UNSIGNED
UNSIGNED indica que un número no puede ser negativo.
stock INT UNSIGNEDEs útil para ids, cantidades o contadores. No lo uses si el campo puede tener valores negativos, y no lo apliques de forma automática a todos los identificadores: solo cuando necesites aprovechar ese rango adicional.
No uses INT(11) para definir capacidad: el ancho de visualización de enteros está obsoleto, al igual que ZEROFILL. El rango depende del tipo y de UNSIGNED, no del número entre paréntesis.
Tipos de texto
| Tipo | Uso habitual |
|---|---|
CHAR | Texto de longitud fija. |
VARCHAR | Texto corto de longitud variable. |
TEXT | Textos largos. |
MEDIUMTEXT | Textos muy largos. |
LONGTEXT | Textos enormes. |
VARCHAR(N) usa longitud variable y es adecuado para nombres, correos, slugs o títulos. Con utf8mb4, cada carácter puede necesitar hasta 4 bytes, y el máximo teórico de un VARCHAR es de 16.383 caracteres, sujeto además al límite de fila y al espacio que ocupen el resto de columnas.
email VARCHAR(255) NOT NULLPara descripciones o contenidos largos, usa TEXT: no es equivalente directo a un VARCHAR. Usa utf8mb4 en lugar de depender de una collation concreta del servidor.
Tipos de fecha y hora
| Tipo | Uso habitual |
|---|---|
DATE | Solo fecha: YYYY-MM-DD. |
TIME | Solo hora: HH:MM:SS. |
DATETIME | Fecha y hora. |
TIMESTAMP | Fecha y hora ligada a zona horaria/registro temporal. |
YEAR | Año. |
La diferencia práctica entre DATETIME y TIMESTAMP está en el rango y la zona horaria:
DATETIMEcubre de 1000 a 9999 y no convierte por zona horaria.TIMESTAMPalmacena y convierte respecto de UTC y de la zona horaria de la sesión, pero su rango termina el 19 de enero de 2038.
Elige DATE cuando solo necesites la fecha, DATETIME para fechas civiles futuras o fuera del rango de TIMESTAMP, y TIMESTAMP cuando su conversión de zona horaria y su rango encajen con el dato.
Ejemplo:
created_at DATETIME NOT NULLNo des por hecho que TIMESTAMP tendrá un valor por defecto automático: ese comportamiento depende de la configuración y de la versión.
Booleanos en MySQL
BOOLEAN es un alias de TINYINT(1), no un tipo lógico independiente.
activo BOOLEAN NOT NULL DEFAULT TRUETambién puedes escribirlo así:
activo TINYINT(1) NOT NULL DEFAULT 1TINYINT(1) no impide guardar otros valores: si necesitas limitar estrictamente a 0 y 1, valídalo desde la aplicación o mediante una restricción adecuada.
Datos binarios
| Tipo | Uso habitual |
|---|---|
BINARY | Datos binarios de longitud fija. |
VARBINARY | Datos binarios de longitud variable. |
BLOB | Archivos o datos binarios. |
Aunque MySQL puede guardar archivos en campos BLOB, muchas veces es mejor guardar el archivo en almacenamiento externo y en la base de datos solo su ruta o identificador.
Datos JSON
configuracion JSONEn este ejemplo ilustrativo, la tabla ajustes tiene una columna configuracion:
SELECT configuracion->'$.tema' AS tema_json,
configuracion->>'$.tema' AS tema_texto
FROM ajustes;Con el documento {"tema":"oscuro"}, -> extrae el valor JSON string, que se representa con comillas ("oscuro"); ->> lo descomilla y devuelve el texto oscuro.
MySQL valida el documento JSON al insertarlo y lo guarda en un formato binario propio. Una columna JSON no se indexa directamente: si necesitas indexar rutas concretas, se usan columnas generadas con sus índices, y los arrays pueden requerir índices multivalor según el caso.
Recomendaciones rápidas
- Elige el tipo por el dato real, no por costumbre:
DECIMALpara importes,VARCHARpara textos cortos yTEXTpara textos largos. - Reserva
FLOATyDOUBLEpara valores aproximados, nunca para dinero. - Usa
utf8mb4y no dependas de una collation concreta del servidor. - Ten en cuenta el rango de
TIMESTAMPantes de usarlo en fechas lejanas. - No guardes números en campos de texto si luego vas a calcular con ellos.
- Define
NOT NULLcuando el dato sea obligatorio y añade valores por defecto cuando tenga sentido.