🎨 Sysprovider Code
Sysprovider LogoWiki
🇪🇸Hosting español para ecommerce

Optimización de Base de Datos MySQL en WordPress para Alto Tráfico

Actualizado el 8 de diciembre de 2025

Introducción: Cuando WordPress Deja de Ser un Blog y se Convierte en una Plataforma de Alto Tráfico

WordPress, por defecto, está optimizado para sitios de baja a media concurrencia. Sin embargo, cuando las visitas superan las decenas de miles al día, el cuello de botella principal suele ser la base de datos MySQL. Sin una optimización MySQL adecuada, el servidor puede colapsar, generando errores 500, lentitud extrema o incluso la caída total del sitio.

En este artículo, exploraremos las técnicas más efectivas para transformar tu base de datos de WordPress en un motor capaz de soportar WordPress alto tráfico. Hablaremos de caching consultas, configuración de índices, replicación MySQL y ajustes del motor de almacenamiento. No basta con tener un buen hosting; necesitas afinar cada tornillo.


## Diagnóstico Inicial: Identificar los Cuellos de Botella

Antes de optimizar, debes medir. Sin datos, cualquier cambio es un tiro en la oscuridad.

### Herramientas Esenciales

  1. Query Monitor: Plugin gratuito que muestra en el frontend todas las consultas SQL ejecutadas, su tiempo y el número de llamadas.
  2. Slow Query Log de MySQL: Actívalo en tu servidor para capturar consultas que tardan más de un segundo.
  3. New Relic / Datadog: Soluciones SaaS que monitorizan el rendimiento de la base de datos en tiempo real.

[INFO] El Slow Query Log se activa en my.cnf con la directiva slow_query_log = 1 y long_query_time = 1. Luego analiza el log con mysqldumpslow.

### Señales de Alarma Comunes

  • Tiempo de consulta promedio superior a 0.5 segundos.
  • Tablas como wp_options con más de 500,000 filas.
  • Uso constante de CPU en MySQL al 80% o más.
  • Consultas del tipo ORDER BY RAND() en los logs lentos.

## Configuración del Motor de Almacenamiento: InnoDB vs MyISAM

WordPress moderno (5.5+) recomienda InnoDB como motor por defecto. Sin embargo, muchos sitios antiguos aún usan MyISAM. Para WordPress alto tráfico, InnoDB es obligatorio por su soporte de bloqueo a nivel de fila y transacciones.

### Migración a InnoDB

Para convertir tablas clave:

ALTER TABLE wp_posts ENGINE=InnoDB;
ALTER TABLE wp_postmeta ENGINE=InnoDB;
ALTER TABLE wp_options ENGINE=InnoDB;
ALTER TABLE wp_comments ENGINE=InnoDB;

[WARNING] No conviertas todas las tablas a InnoDB de golpe. Tablas como wp_actionscheduler_actions pueden requerir configuraciones específicas de índices. Hazlo de una en una.

### Ajustes Clave en my.cnf para InnoDB

[mysqld]
# Tamaño del buffer de InnoDB (70-80% de la RAM disponible si solo tienes MySQL)
innodb_buffer_pool_size = 4G

# Tamaño del log de transacciones (25% del buffer pool)
innodb_log_file_size = 1G

# Número de hilos de I/O para InnoDB
innodb_io_capacity = 2000
innodb_io_capacity_max = 3000

# Desactivar el doble buffer si usas discos SSD (mejora rendimiento)
innodb_flush_method = O_DIRECT

## Caching de Consultas: El Primer Paso para Reducir la Carga

El caching consultas es la técnica más inmediata para mejorar el rendimiento base datos. Consiste en almacenar en memoria el resultado de consultas SELECT repetitivas para no tener que ejecutarlas contra la base de datos.

### Query Cache de MySQL (Obsoleto en MySQL 8.0)

En MySQL 5.7 y anteriores, el query cache podía ser útil, pero en versiones modernas (8.0+) está eliminado. Si usas MySQL 5.7, ajústalo con moderación:

query_cache_type = 1
query_cache_size = 256M
query_cache_limit = 2M

[TIP] Si tienes un sitio con muchas escrituras (por ejemplo, WooCommerce), el query cache puede ser contraproducente porque se invalida constantemente. En ese caso, mejor desactivarlo.

### Caching a Nivel de Aplicación (Recomendado)

Para WordPress alto tráfico, es mejor evitar el query cache de MySQL y usar soluciones como:

  • Redis: Almacena en RAM los resultados de consultas y objetos de WordPress.
  • Memcached: Similar a Redis pero más simple.

Configura un plugin como Redis Object Cache para que WordPress almacene en Redis los resultados de consultas como wp_get_post_meta() y WP_Query.

# Instalar Redis en Ubuntu
sudo apt install redis-server
sudo systemctl enable redis-server

# Configurar PHP para usar Redis
sudo apt install php-redis
sudo systemctl restart php8.1-fpm

## Índices: La Clave para Consultas Relámpago

Sin índices, MySQL escanea tabla completa cada vez que buscas un dato. Para optimización MySQL, los índices son tu mejor amigo.

### Índices Esenciales en WordPress

WordPress ya crea índices básicos, pero algunos faltan para alto tráfico:

-- Índice compuesto para consultas de meta queries
ALTER TABLE wp_postmeta ADD INDEX meta_key_value (meta_key, meta_value(100));

-- Índice para wp_options (comúnmente consultado por option_name)
ALTER TABLE wp_options ADD INDEX option_name_index (option_name);

-- Índice para wp_usermeta (útil para sitios con muchos usuarios)
ALTER TABLE wp_usermeta ADD INDEX user_meta_key (user_id, meta_key);

### Cómo Identificar Índices Faltantes

Ejecuta este comando en MySQL para ver las consultas lentas y qué índices recomienda:

SELECT * FROM sys.schema_unused_indexes;

O usa la herramienta pt-query-digest de Percona Toolkit para analizar los logs lentos y sugerir índices.


## Replicación MySQL: Escalabilidad Horizontal

Cuando una sola instancia de MySQL no es suficiente, la replicación MySQL permite distribuir la carga. En WordPress, esto se traduce en:

  • Maestro: Maneja todas las escrituras (INSERT, UPDATE, DELETE).
  • Esclavos: Manejan todas las lecturas (SELECT). Pueden ser múltiples.

### Configuración Básica de Replicación

  1. En el Maestro (my.cnf):

    server-id = 1
    log_bin = /var/log/mysql/mysql-bin.log
    binlog_do_db = wordpress_db
    
  2. Crear usuario de replicación:

    CREATE USER 'replicator'@'%' IDENTIFIED BY 'password';
    GRANT REPLICATION SLAVE ON *.* TO 'replicator'@'%';
    FLUSH PRIVILEGES;
    
  3. En el Esclavo (my.cnf):

    server-id = 2
    relay-log = /var/log/mysql/mysql-relay-bin.log
    read_only = 1
    
  4. Conectar Esclavo al Maestro:

    CHANGE MASTER TO
      MASTER_HOST='master_ip',
      MASTER_USER='replicator',
      MASTER_PASSWORD='password',
      MASTER_LOG_FILE='mysql-bin.000001',
      MASTER_LOG_POS=0;
    START SLAVE;
    

### WordPress con Replicación

Para que WordPress use el maestro para escrituras y esclavos para lecturas, necesitas un plugin como LudicrousDB o HyperDB (de Automattic). Configura un array de servidores en wp-config.php:

$wpdb->add_database(array(
    'host'     => 'maestro_ip',
    'user'     => 'user',
    'password' => 'pass',
    'name'     => 'wordpress_db',
    'write'    => 1,
    'read'     => 0,
));

$wpdb->add_database(array(
    'host'     => 'esclavo1_ip',
    'user'     => 'user',
    'password' => 'pass',
    'name'     => 'wordpress_db',
    'write'    => 0,
    'read'     => 1,
));

[WARNING] La replicación introduce latencia. Asegúrate de que las lecturas puedan tolerar datos ligeramente desactualizados (eventual consistency). Para páginas de administración, fuerza el uso del maestro.


## Limpieza y Mantenimiento: La Base de Datos No se Mantiene Sola

Una base de datos descuidada se llena de basura: revisiones de posts, transients caducados, spam de comentarios, etc.

### Tablas a Limpiar Periódicamente

  • wp_posts: Elimina revisiones antiguas (más de 5 por post).
  • wp_postmeta: Metadatos huérfanos de posts eliminados.
  • wp_options: Transients caducados (claves que empiezan por _transient_).
  • wp_actionscheduler_actions: Acciones programadas completadas (común en WooCommerce).

### Script de Limpieza SQL

-- Eliminar revisiones de posts (deja solo las últimas 5 por post)
DELETE FROM wp_posts
WHERE post_type = 'revision'
AND ID NOT IN (
    SELECT ID FROM (
        SELECT ID
        FROM wp_posts
        WHERE post_type = 'revision'
        ORDER BY post_date DESC
        LIMIT 18446744073709551615
    ) AS tmp
);

-- Eliminar transients caducados
DELETE FROM wp_options WHERE option_name LIKE '%\_transient\_%' AND option_value < UNIX_TIMESTAMP();

### Plugin Recomendado

  • WP-Optimize: Automatiza la limpieza y optimización de tablas.
  • Advanced Database Cleaner: Más granular, permite limpiar por tipo de dato.

## Configuración de Conexiones y Pooling

Cada petición a WordPress abre una conexión MySQL. Con alto tráfico, el número de conexiones simultáneas puede agotar los recursos.

### Límites en my.cnf

max_connections = 500
thread_cache_size = 100
wait_timeout = 60
interactive_timeout = 120

### Usar un Pool de Conexiones (ProxySQL)

ProxySQL actúa como intermediario entre WordPress y MySQL, manteniendo un pool de conexiones persistentes. Reduce el overhead de crear/destruir conexiones.

# Instalar ProxySQL
sudo apt install proxysql2
sudo systemctl start proxysql

# Configurar en /etc/proxysql.cnf
mysql_servers:
(
    { address="maestro_ip", port=3306, hostgroup=10 },
    { address="esclavo_ip", port=3306, hostgroup=20 }
)

mysql_query_rules:
(
    { rule_id=1, active=1, match_pattern="^SELECT", destination_hostgroup=20, apply=1 },
    { rule_id=2, active=1, match_pattern=".*", destination_hostgroup=10, apply=1 }
)

Luego, en wp-config.php, cambia el host de la base de datos a la IP de ProxySQL (puerto 6033).


## Conclusión: La Optimización es un Proceso Continuo

La optimización MySQL para WordPress alto tráfico no es una tarea única. Es un ciclo constante de medición, ajuste y mantenimiento. Desde el caching consultas con Redis, pasando por la creación de índices inteligentes, hasta la replicación MySQL con ProxySQL, cada capa añade resiliencia.

[TIP] No implementes todos los cambios a la vez. Hazlo por fases: primero el caching, luego los índices, después la replicación. Mide el impacto de cada cambio con herramientas como Query Monitor o New Relic.

Recuerda: una base de datos optimizada no solo acelera el sitio, sino que reduce el coste de hosting porque necesitas menos recursos para servir el mismo tráfico. La base de datos es el corazón de WordPress; mantenlo latiendo fuerte.

¿Necesitas ayuda?Son dos de nuestros técnicos, Agustín y Mikel, y están disponibles para resolver cualquier problema.

Hablar con ellos ahora
Agustín y Mikel