Cuando empiezas a aprender bases de datos relacionales, tarde o temprano aparece la misma pregunta: ¿MySQL o PostgreSQL? Los dos son gratuitos, los dos usan SQL, los dos son open source y los dos están entre las bases de datos más usadas del mundo.
¿Por qué existen los dos entonces? ¿Cuál deberías aprender primero? ¿Cuándo cambia la respuesta?
En este artículo vas a entender qué es cada uno, en qué se diferencian de verdad, cuáles son sus fortalezas reales y cuándo elegir uno sobre el otro. Con ejemplos de código donde las diferencias importan.
¿Qué es MySQL?
MySQL es un sistema de gestión de bases de datos relacionales (RDBMS) de código abierto lanzado en 1995 por la empresa sueca MySQL AB. Fue adquirido por Sun Microsystems en 2008 y luego por Oracle en 2010, quien lo mantiene hasta hoy.
Es la base de datos relacional de código abierto más usada del mundo. Potencia más del 43% de todos los sitios web a través de WordPress, es el componente de base de datos del stack LAMP (Linux, Apache, MySQL, PHP) y es usado por empresas como Twitter, YouTube, Facebook (en sus inicios) y Wikipedia.
Su filosofía: ser simple, rápida y fácil de usar. Sacrifica algunas funcionalidades avanzadas a cambio de menor complejidad y mayor velocidad en cargas de trabajo de lectura.
¿Qué es PostgreSQL?
PostgreSQL (pronunciado "post-gres-Q-L", o simplemente "Postgres") es un sistema de gestión de bases de datos objeto-relacional (ORDBMS) de código abierto con más de 35 años de desarrollo activo. Su origen se remonta a 1986 en la Universidad de California Berkeley, como proyecto académico llamado POSTGRES.
A diferencia de MySQL, PostgreSQL no está controlado por ninguna empresa. Es gestionado por el PostgreSQL Global Development Group, una comunidad global de voluntarios y contribuidores. Eso le da una independencia que MySQL, controlado por Oracle, no tiene.
Su filosofía: ser el sistema de bases de datos open source más avanzado del mundo, con pleno cumplimiento de los estándares SQL y extensibilidad máxima. No sacrifica funcionalidad por simplicidad.
En 2026, PostgreSQL lleva varios años consecutivos siendo la base de datos de crecimiento más rápido y es la opción predeterminada en la mayoría de las plataformas cloud.
Lo que tienen en común
Antes de las diferencias, es importante destacar lo que comparten, porque son muchas cosas:
- ✅ Ambos son relacionales — usan tablas, filas, columnas y SQL
- ✅ Ambos son gratuitos y open source
- ✅ Ambos soportan transacciones ACID — atomicidad, consistencia, aislamiento, durabilidad
- ✅ Ambos tienen claves primarias y foráneas, índices, vistas y triggers
- ✅ Ambos soportan replicación para alta disponibilidad
- ✅ Ambos funcionan en Linux, Windows y macOS
- ✅ Ambos tienen drivers para todos los lenguajes — Python, Node.js, Java, PHP, Ruby...
- ✅ Para la mayoría de aplicaciones web comunes, cualquiera de los dos funciona perfectamente
La diferencia de rendimiento entre ambos para cargas de trabajo típicas es, según múltiples benchmarks, de menos del 30%. La elección correcta del índice importa mucho más que qué base de datos usas.
Las diferencias que realmente importan
1. 🏗️ Arquitectura: Relacional vs Objeto-Relacional
MySQL: RDBMS (Relational Database Management System)
→ base de datos puramente relacional
→ tablas sin herencia ni tipos personalizados
PostgreSQL: ORDBMS (Object-Relational Database Management System)
→ combina el modelo relacional con conceptos de OOP
→ soporta herencia de tablas, tipos personalizados,
sobrecarga de funciones-- PostgreSQL: herencia de tablas (no existe en MySQL)
CREATE TABLE vehiculos (
id SERIAL PRIMARY KEY,
marca VARCHAR(50),
modelo VARCHAR(50),
anio INT
);
-- coches hereda todos los campos de vehiculos
CREATE TABLE coches (
num_puertas INT,
tipo_cambio VARCHAR(20)
) INHERITS (vehiculos);
-- motos hereda todos los campos de vehiculos
CREATE TABLE motos (
cilindrada INT,
tipo VARCHAR(20) -- deportiva, cruiser, etc.
) INHERITS (vehiculos);
-- Una consulta en vehiculos devuelve también los datos de coches y motos
SELECT * FROM vehiculos; -- devuelve todos los vehículos2. 📦 Tipos de datos — PostgreSQL gana con diferencia
Esta es una de las diferencias más prácticas. PostgreSQL soporta una variedad de tipos de datos que MySQL simplemente no tiene:
| Tipo de dato | MySQL | PostgreSQL | ¿Para qué sirve? |
|---|---|---|---|
| Enteros, strings, fechas | ✅ | ✅ | Datos básicos |
| BOOLEAN nativo | 🔶 TINYINT(1) | ✅ TRUE/FALSE | Valores verdadero/falso |
| JSON | ✅ básico | ✅ JSON + JSONB | Datos semiestructurados |
| ARRAY | ❌ | ✅ nativo | Listas de valores en una celda |
| UUID | 🔶 VARCHAR | ✅ tipo nativo | Identificadores únicos globales |
| Tipos geométricos | ❌ | ✅ POINT, LINE, POLYGON | Datos espaciales básicos |
| Tipos de red | ❌ | ✅ INET, CIDR, MACADDR | Direcciones IP, MAC |
| Rangos | ❌ | ✅ int4range, daterange | Intervalos de valores |
| hstore | ❌ | ✅ | Pares clave-valor en una columna |
| Tipos personalizados | ❌ | ✅ CREATE TYPE | Enumerados y tipos compuestos |
-- PostgreSQL: usando ARRAY (no disponible en MySQL)
CREATE TABLE productos (
id SERIAL PRIMARY KEY,
nombre VARCHAR(100),
etiquetas TEXT[], -- array de strings
precios DECIMAL(10,2)[] -- array de precios por zona
);
INSERT INTO productos (nombre, etiquetas, precios)
VALUES ('Laptop Pro', ARRAY['tecnologia', 'premium', 'oferta'], ARRAY[899.99, 849.99, 920.00]);
-- Buscar productos con una etiqueta específica
SELECT nombre FROM productos WHERE 'premium' = ANY(etiquetas);
-- PostgreSQL: tipo UUID nativo
CREATE TABLE usuarios (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
email VARCHAR(100) UNIQUE
);
-- PostgreSQL: tipos de red
CREATE TABLE servidores (
id SERIAL PRIMARY KEY,
nombre VARCHAR(50),
ip_address INET, -- valida formato IP automáticamente
subred CIDR
);
INSERT INTO servidores VALUES (1, 'web-01', '192.168.1.100', '192.168.1.0/24');3. 🔄 JSON y JSONB — la ventaja más práctica de PostgreSQL
Ambas bases de datos soportan JSON, pero de formas muy distintas. PostgreSQL tiene dos tipos: JSON (almacena el texto tal cual) y JSONB (almacena en formato binario optimizado). JSONB es indexable, consultable y mucho más rápido para búsquedas.
-- PostgreSQL: JSONB con índices y consultas potentes
CREATE TABLE eventos (
id SERIAL PRIMARY KEY,
datos JSONB -- formato binario, indexable
);
INSERT INTO eventos (datos) VALUES
('{"usuario": "ana", "accion": "compra", "total": 299.99, "items": ["laptop", "mouse"]}'),
('{"usuario": "luis", "accion": "vista", "producto": "teclado"}');
-- Crear índice GIN sobre el JSONB (muy eficiente)
CREATE INDEX idx_eventos_datos ON eventos USING GIN(datos);
-- Consultar dentro del JSON con operadores nativos
SELECT datos->>'usuario' AS usuario,
datos->>'total' AS total
FROM eventos
WHERE datos->>'accion' = 'compra'
AND (datos->>'total')::DECIMAL > 100;
-- Buscar si un array JSON contiene un valor
SELECT * FROM eventos
WHERE datos->'items' ? 'laptop';-- MySQL: JSON funcional pero más limitado
-- No tiene JSONB, los índices sobre JSON son más complejos
SELECT JSON_EXTRACT(datos, '$.usuario') AS usuario
FROM eventos
WHERE JSON_EXTRACT(datos, '$.accion') = 'compra';4. 🔒 Concurrencia: MVCC vs bloqueos de escritura
Este es el punto técnico más importante para aplicaciones con alta concurrencia:
MySQL (motor InnoDB):
Usa bloqueos de escritura.
Cuando un usuario escribe en una tabla,
otros usuarios que lean esa tabla pueden esperar.
En cargas muy concurrentes de escritura, puede generar cuellos de botella.
PostgreSQL:
Usa MVCC (Multi-Version Concurrency Control).
Cada transacción ve una "instantánea" coherente de los datos.
Los lectores nunca bloquean a los escritores.
Los escritores nunca bloquean a los lectores.
Ideal para aplicaciones con muchas escrituras simultáneas.En la práctica: para aplicaciones con pocas escrituras (blogs, catálogos, sitios informativos), la diferencia es irrelevante. Para sistemas con miles de usuarios escribiendo simultáneamente (plataformas transaccionales, e-commerce con mucho tráfico), el MVCC de PostgreSQL marca una diferencia real.
5. ⚡ Rendimiento: cada uno en su terreno
MySQL es más rápido para:
✅ Consultas SELECT simples (lectura pura)
✅ Aplicaciones "read-heavy" con datos sencillos
✅ WordPress y CMS similares
✅ Aplicaciones con muchas conexiones cortas y simples
PostgreSQL es más rápido para:
✅ Consultas complejas con CTEs, window functions y subqueries
✅ Operaciones con JSON/JSONB
✅ Cargas de trabajo analíticas (muchos GROUP BY, JOINs)
✅ Escrituras concurrentes intensas
✅ Data Science y Machine Learning6. 📋 Cumplimiento del estándar SQL
PostgreSQL es conocido por su estricto cumplimiento del estándar SQL ANSI/ISO. MySQL tiene su propio dialecto con algunas diferencias:
-- Window Functions (funciones de ventana)
-- PostgreSQL: soporte completo y robusto desde hace años
-- MySQL: soporte desde MySQL 8.0 (2018), más limitado
SELECT
nombre,
departamento,
salario,
RANK() OVER (PARTITION BY departamento ORDER BY salario DESC) AS ranking,
AVG(salario) OVER (PARTITION BY departamento) AS media_depto,
LAG(salario) OVER (ORDER BY salario) AS salario_anterior
FROM empleados;
-- CTEs recursivas (Common Table Expressions)
-- PostgreSQL: soporte completo
-- MySQL: soporte desde 8.0, con algunas limitaciones
WITH RECURSIVE jerarquia AS (
SELECT id, nombre, jefe_id, 0 AS nivel
FROM empleados WHERE jefe_id IS NULL -- director
UNION ALL
SELECT e.id, e.nombre, e.jefe_id, j.nivel + 1
FROM empleados e
INNER JOIN jerarquia j ON e.jefe_id = j.id
)
SELECT * FROM jerarquia ORDER BY nivel, nombre;
-- CHECK constraints
-- PostgreSQL: se aplican siempre
-- MySQL: las parsea pero históricamente las IGNORABA (corregido en 8.0.16)
CREATE TABLE productos (
precio DECIMAL(10,2),
CHECK (precio > 0) -- PostgreSQL siempre lo aplica; MySQL legacy lo ignoraba
);7. 🔌 Extensibilidad — la superpotencia de PostgreSQL
-- PostgreSQL permite instalar extensiones que añaden funcionalidades enormes
-- PostGIS: datos geoespaciales avanzados
CREATE EXTENSION postgis;
SELECT ST_Distance(
ST_MakePoint(-3.7038, 40.4168), -- Madrid
ST_MakePoint(2.1734, 41.3851) -- Barcelona
) AS distancia_grados;
-- pg_trgm: búsqueda por similitud de texto (typo-tolerant search)
CREATE EXTENSION pg_trgm;
CREATE INDEX idx_productos_trgm ON productos USING GIN(nombre gin_trgm_ops);
SELECT nombre FROM productos
WHERE nombre % 'lapto' -- encuentra "laptop" aunque esté mal escrito
ORDER BY similarity(nombre, 'lapto') DESC;
-- pgvector: búsqueda vectorial para IA (embeddings)
CREATE EXTENSION vector;
CREATE TABLE documentos (
id SERIAL PRIMARY KEY,
contenido TEXT,
embedding VECTOR(1536) -- embeddings de OpenAI/Claude
);
-- Búsqueda de similitud semántica con nearest neighbors
SELECT contenido FROM documentos
ORDER BY embedding <-> '[0.1, 0.2, ...]'::vector
LIMIT 5;
-- uuid-ossp: generación de UUIDs
CREATE EXTENSION "uuid-ossp";
SELECT uuid_generate_v4();MySQL no tiene un sistema de extensiones equivalente. Sus funcionalidades son más fijas.
8. 📜 Licencia — un detalle que importa en empresas
MySQL: GPL v2 (edición Community)
→ Si distribuyes software que usa MySQL, puedes necesitar
publicar tu código fuente (copyleft)
→ La empresa propietaria es Oracle (algunos se preocupan
por el futuro del proyecto)
→ Edición Enterprise: de pago
PostgreSQL: Licencia PostgreSQL (similar a MIT/BSD)
→ Puedes usar PostgreSQL en software propietario sin
obligación de publicar tu código
→ Sin restricciones para uso comercial
→ Nadie controla el proyecto — es genuinamente comunitario
→ Todo gratuito, sin edición "Enterprise" de pago9. ☁️ Soporte en la nube
AWS:
RDS for MySQL → MySQL gestionado
RDS for PostgreSQL → PostgreSQL gestionado
Aurora MySQL → MySQL compatible, más rápido
Aurora PostgreSQL → PostgreSQL compatible, más rápido
Google Cloud:
Cloud SQL for MySQL
Cloud SQL for PostgreSQL
AlloyDB → PostgreSQL compatible, optimizado para cloud
Azure:
Azure Database for MySQL
Azure Database for PostgreSQL
Supabase: → solo PostgreSQL (muy popular para startups)
PlanetScale: → solo MySQL compatible
Neon: → solo PostgreSQL (serverless)Diferencias de sintaxis que debes conocer
-- ============================================================
-- AUTO INCREMENT
-- ============================================================
-- MySQL:
CREATE TABLE usuarios (
id INT AUTO_INCREMENT PRIMARY KEY,
nombre VARCHAR(100)
);
-- PostgreSQL (SERIAL o GENERATED ALWAYS AS IDENTITY):
CREATE TABLE usuarios (
id SERIAL PRIMARY KEY, -- o: id INT GENERATED ALWAYS AS IDENTITY
nombre VARCHAR(100)
);
-- ============================================================
-- LÍMITE DE RESULTADOS
-- ============================================================
-- MySQL y PostgreSQL (igual):
SELECT * FROM productos ORDER BY precio DESC LIMIT 10;
-- PostgreSQL también soporta OFFSET:
SELECT * FROM productos ORDER BY precio LIMIT 10 OFFSET 20; -- página 3
-- ============================================================
-- CONCATENACIÓN DE STRINGS
-- ============================================================
-- MySQL: función CONCAT()
SELECT CONCAT(nombre, ' ', apellido) AS nombre_completo FROM clientes;
-- PostgreSQL: operador || (estándar SQL)
SELECT nombre || ' ' || apellido AS nombre_completo FROM clientes;
-- (PostgreSQL también acepta CONCAT)
-- ============================================================
-- IFNULL / COALESCE
-- ============================================================
-- MySQL:
SELECT IFNULL(telefono, 'Sin teléfono') FROM clientes;
-- PostgreSQL (COALESCE funciona en ambos, es el estándar):
SELECT COALESCE(telefono, 'Sin teléfono') FROM clientes;
-- ============================================================
-- VISTAS MATERIALIZADAS
-- ============================================================
-- PostgreSQL: soporte nativo completo
CREATE MATERIALIZED VIEW resumen_ventas AS
SELECT categoria, SUM(total) AS total_mes
FROM ventas WHERE fecha >= CURRENT_DATE - INTERVAL '30 days'
GROUP BY categoria;
-- Actualizar la vista materializada
REFRESH MATERIALIZED VIEW resumen_ventas;
-- MySQL: no tiene vistas materializadas nativas
-- Se simula con tablas regulares y eventos programados¿Cuándo usar cada uno? — La guía de decisión definitiva
Elige MySQL cuando:
- ✅ Estás construyendo un sitio con WordPress, Joomla o Drupal
- ✅ Tu aplicación es principalmente de lectura con datos simples
- ✅ Es tu primera base de datos y quieres empezar con algo más simple
- ✅ El stack es LAMP o LEMP (Linux, Apache/Nginx, MySQL, PHP)
- ✅ El equipo ya tiene experiencia sólida con MySQL
- ✅ Necesitas compatibilidad con herramientas específicas del ecosistema MySQL
Elige PostgreSQL cuando:
- ✅ Necesitas tipos de datos avanzados: JSONB, ARRAY, UUID, geométricos
- ✅ Tu aplicación tiene escrituras concurrentes intensas
- ✅ Estás construyendo algo orientado a datos, analítica o Machine Learning
- ✅ Necesitas extensiones como PostGIS, pgvector o pg_trgm
- ✅ Quieres máxima conformidad con el estándar SQL
- ✅ Estás usando Supabase, Neon o plataformas modernas que solo soportan Postgres
- ✅ Tu proyecto es empresarial y necesitas vistas materializadas, CTEs complejas
- ✅ Empiezas un proyecto nuevo — en 2026 PostgreSQL es la recomendación por defecto
💡 La regla práctica de 2026: para la mayoría de proyectos nuevos, PostgreSQL es la opción recomendada por su mejor soporte de JSON, tipos de datos nativos, superior búsqueda de texto completo y mejor concurrencia con MVCC. Elige MySQL si construyes sobre WordPress o necesitas compatibilidad con herramientas del ecosistema MySQL.
Stacks populares con cada base de datos
Stacks típicos con MySQL:
LAMP: Linux + Apache + MySQL + PHP
LEMP: Linux + Nginx + MySQL + PHP
WordPress, Magento, Drupal, Joomla
Stacks típicos con PostgreSQL:
Django + PostgreSQL (Python)
Rails + PostgreSQL (Ruby)
FastAPI + PostgreSQL (Python)
NestJS + PostgreSQL (Node.js / TypeScript)
Next.js + Supabase (PostgreSQL en la nube)
Spring + PostgreSQL (Java)Tabla comparativa completa
| Característica | MySQL | PostgreSQL |
|---|---|---|
| Primer lanzamiento | 1995 | 1996 (origen en 1986) |
| Propietario | Oracle (desde 2010) | Comunidad open source |
| Licencia | GPL v2 (con restricciones) | Licencia PostgreSQL (tipo MIT) |
| Tipo | RDBMS puro | ORDBMS (objeto-relacional) |
| Cumplimiento SQL | Parcial | Muy alto |
| MVCC | Parcial (InnoDB) | Completo y nativo |
| JSON | JSON básico | JSON + JSONB (indexable) |
| Arrays nativos | ❌ | ✅ |
| Extensiones | Limitado | Muy rico (PostGIS, pgvector…) |
| Vistas materializadas | ❌ | ✅ |
| Rendimiento lecturas simples | Ligeramente mejor | Muy bueno |
| Rendimiento consultas complejas | Bueno | Superior |
| Curva de aprendizaje | Más suave | Algo más pronunciada |
| Ecosistema web | Muy grande (WordPress) | Creciente |
| Tendencia 2026 | Estable | Crecimiento acelerado |
Resumen: lo que aprendiste hoy
- ✅ MySQL nació en 1995 y es el más usado globalmente, especialmente en WordPress y stacks LAMP
- ✅ PostgreSQL nació en 1996 (con raíces en 1986) y es el más avanzado funcionalmente
- ✅ MySQL es RDBMS puro; PostgreSQL es ORDBMS con capacidades objeto-relacionales
- ✅ PostgreSQL tiene tipos nativos que MySQL no tiene: ARRAY, UUID, tipos de red, rangos, JSONB indexable
- ✅ El MVCC de PostgreSQL gestiona la concurrencia sin bloqueos de lectura — mejor para escrituras intensas
- ✅ MySQL es ligeramente más rápido en lecturas simples; PostgreSQL domina en consultas complejas
- ✅ PostgreSQL tiene la licencia más permisiva — puede usarse en software propietario sin restricciones
- ✅ Las extensiones de PostgreSQL (PostGIS, pgvector, pg_trgm) amplían enormemente sus capacidades
- ✅ En 2026, PostgreSQL es la recomendación por defecto para proyectos nuevos
- ✅ MySQL sigue siendo la elección correcta para WordPress, stacks LAMP y equipos con experiencia MySQL
🧪 ¿Tienes los fundamentos de SQL bien sólidos?
Tanto MySQL como PostgreSQL usan SQL. Dominar los conceptos fundamentales — SELECT, JOIN, GROUP BY, subconsultas e índices — es lo que te permitirá aprovechar al máximo cualquiera de las dos. Comprueba dónde estás:
👉 Test: SQL Básico 👉 Test: SQL vs NoSQL
¿Ya usabas alguna de las dos antes de leer este artículo? ¿Con cuál vas a empezar — o con cuál seguirás? ¿Alguna diferencia te sorprendió especialmente? Cuéntanos en los comentarios 👇 — respondemos todos. 🚀
No hay comentarios todavía. Sé el primero en compartir tu opinión.