Base de datos WordPress hinchada: limpieza de wp_options autoload sin romper nada

¿Te fue útil?

Cuando WordPress se vuelve “misteriosamente lento”, el culpable a menudo no es PHP, ni el tema, ni siquiera tu servidor de base de datos. Es un patrón de una sola fila de tabla: wp_options lleno de megabytes de basura autoload que WordPress carga en memoria en cada petición.

Lo notas como aumento del TTFB, picos aleatorios durante ráfagas de tráfico, páginas de administración que se sienten como conexión por marcación y CPU de la base de datos que está ociosa hasta que de repente no lo está. ¿La mejor parte? El sitio puede seguir “funcionando” hasta que deja de hacerlo. Limpémoslo de forma segura, como adultos que gestionan sistemas en producción.

Índice

Qué significa realmente autoload (y por qué perjudica)

wp_options es el “cajón para todo” de WordPress. Ajustes, estado de plugins, caches, banderas de características, tokens API, cron schedules y valores “temporales” que viven para siempre—la mayoría termina aquí.

El campo clave: autoload. Si una opción tiene autoload='yes', WordPress intentará cargarla temprano (vía wp_load_alloptions()) para poder servir peticiones sin muchas consultas pequeñas. Es una buena idea cuando los datos autoloaded son pequeños y estables. Es una mala idea cuando son 10–100+ MB de arrays serializados, configuraciones de widgets, caches gigantes de plugins y los sueños rotos de un plugin de marketing que nunca conoció una base de datos a la que no quisiera sobrecompartir.

Este es el modo de fallo: las opciones autoloaded se obtienen en la mayoría de las peticiones (front-end y admin). Incluso si tienes un object cache, esos valores aún deben cargarse en memoria al menos una vez por ciclo de caché y a menudo se copian/serializan. Cuanto más crece, más CPU y memoria quemas, y más amplificas la latencia durante pérdidas de caché, despliegues, reinicios de pods o failovers.

Una verdad seca: no “optimizar MySQL” te salva de esto. Dejas de autoloadear basura.

Broma corta #1: El bloat de autoload es como el cajón de las cosas inútiles: empieza con una pila extra y termina con tres llaves misteriosas y un destornillador diminuto que no puedes tirar.

Autoload no es “caché”

Las opciones autoloaded no son una caché inteligente con semántica TTL. Son “cárgalo siempre porque alguien supuso que era necesario”. Esa suposición suele ser errónea, especialmente para plugins que almacenan estructuras computadas grandes o logs como opciones.

Por qué afecta el rendimiento de forma rara y por ráfagas

  • Arranques en frío: Reinicios de FPM, reprogramación de contenedores, nuevas instancias escalando—las opciones autoloaded necesitan calentarse. Ahí es cuando el sitio se vuelve más lento.
  • Rotación de object cache: Si tu object cache expulsa con frecuencia, recargas datos autoloaded más a menudo de lo que crees.
  • Retraso en replicación: Las actualizaciones de opciones grandes crean binlogs/cambios de filas más grandes, aumentando el lag bajo carga.
  • Bloqueos/IO: Actualizar opciones grandes puede significar escrituras pesadas y, en almacenamiento compartido o discos saturados, pagas en latencia.

Guía rápida de diagnóstico

Si un sitio WordPress está lento y sospechas bloat en wp_options autoload, no te pierdas. Revisa tres cosas en este orden:

1) ¿Los datos autoloaded son enormes?

Ejecuta una suma rápida de los tamaños de opciones autoloaded. Si está por encima de unos pocos MB, tienes una pista. Si son decenas de MB, tienes al culpable.

2) ¿Qué opciones están causando el daño?

Encuentra a los principales ofensores por tamaño. Buscas arrays serializados gigantes, caches de plugins y cualquier cosa que claramente no necesite cargarse en cada petición.

3) ¿La lentitud está ligada a pérdidas de caché/reinicios?

Correlaciona picos con reinicios de FPM, reprogramación de contenedores o expulsiones de Redis/Memcached. El bloat de autoload amplifica el dolor de los arranques en frío.

Luego decide: borra basura obvia (transients expirados, restos de plugins) y cambia “grande pero necesario a veces” de autoloaded a no-autoloaded, idealmente reemplazándolo con una caché adecuada.

Hechos e historia interesantes que puedes usar

  1. Las opciones de WordPress preceden a muchos plugins modernos: la API de opciones fue diseñada para ajustes pequeños, no para blobs a escala megabyte.
  2. Autoload se ideó para reducir el conteo de consultas: en los primeros días, muchas consultas pequeñas eran el mal mayor que el consumo de memoria.
  3. Los arrays PHP serializados facilitaron almacenar cualquier cosa: también facilitaron almacenar todo para siempre, sin presión de esquema.
  4. Los transients se introdujeron como “caché temporal”: pero sin un object cache persistente, los transients a menudo viven en wp_options y se acumulan.
  5. Muchos plugins usan wp_options como vertedero: porque está disponible universalmente, no porque sea apropiado.
  6. Los sitios WooCommerce son víctimas frecuentes: no porque WooCommerce sea inherentemente malo, sino porque la alta densidad de plugins aumenta la rotación de opciones.
  7. El autoload bloat puede esconderse detrás de un CDN: las páginas siguen “cargando rápido” desde caché, hasta que la caché expira o un usuario autenticado accede a endpoints dinámicos.
  8. El tamaño de la base de datos no es la métrica que importa: una base de datos de 2 GB puede estar bien; una carga autoload de 20 MB en cada petición no lo está.
  9. Algunos hosts “optimizaron” programando OPTIMIZE TABLE: lo cual no soluciona el autoload bloat y puede añadir IO/bloqueos cuando se ejecuta en el momento equivocado.

Mide primero: cómo se ve el “bloat” en números reales

El trabajo en producción comienza con la medición. No con intuiciones. El objetivo es responder:

  • ¿Cuánto pesa la carga autoloaded?
  • ¿Quiénes son los principales ofensores?
  • ¿Está creciendo?
  • ¿Qué es seguro borrar frente a qué solo desactivar autoload?

Reglas prácticas (opinionadas, porque lo pediste):

  • < 1 MB autoload total: probablemente está bien. No generes trabajo innecesario.
  • 1–5 MB: vigílalo; investiga algunos ítems principales.
  • 5–20 MB: estás pagando impuesto de latencia. Límpialo.
  • > 20 MB: estás en territorio de incidente; los arranques en frío serán feos.

Estos umbrales varían con el hardware y el caching. Pero en la práctica, una vez que el autoload cruza “unos pocos MB”, se convierte en un riesgo de fiabilidad porque multiplica el coste de cada evento de pérdida de caché.

Y un mantra de fiabilidad del campo: Todo falla todo el tiempo. — Werner Vogels (idea parafraseada). El autoload bloat convierte esos fallos rutinarios (reinicios, expulsiones) en lentitud visible para el usuario.

Tareas prácticas: comandos, salidas, decisiones (12+)

Estas tareas están escritas para operadores. Incluyen el comando, salida de ejemplo, qué significa y qué decisión tomar. Supón que tienes acceso al shell y WP-CLI o cliente MySQL. Ajusta nombres de BD/prefijos según corresponda.

Task 1: Confirmar prefijo de tabla y credenciales BD (no adivines)

cr0x@server:~$ cd /var/www/html && wp config get table_prefix
wp_

Qué significa: Tu prefijo de tabla es wp_. Si asumiste wp_ y en realidad es wpx9_, cada consulta SQL que ejecutes estará equivocada o será peligrosa.

Decisión: Usa el prefijo devuelto en todas las consultas posteriores. Si WP-CLI no puede leer la config, para y arregla el acceso primero.

Task 2: Encontrar tamaño de payload autoload (rápido y decisivo)

cr0x@server:~$ wp db query "SELECT ROUND(SUM(LENGTH(option_value))/1024/1024,2) AS autoload_mb FROM wp_options WHERE autoload='yes';"
+------------+
| autoload_mb|
+------------+
| 28.74      |
+------------+

Qué significa: ~29 MB se cargan como “alloptions”. Eso no es “un poco lento”. Es un impuesto recurrente en cada petición en frío.

Decisión: Procede a identificar los principales ofensores; planifica una ventana de limpieza controlada.

Task 3: Identificar principales opciones autoloaded por tamaño

cr0x@server:~$ wp db query "SELECT option_name, ROUND(LENGTH(option_value)/1024/1024,2) AS mb FROM wp_options WHERE autoload='yes' ORDER BY LENGTH(option_value) DESC LIMIT 20;"
+------------------------------+------+
| option_name                  | mb   |
+------------------------------+------+
| plugin_x_cache_blob          | 12.40|
| widget_custom_html           | 4.12 |
| rewrite_rules                | 2.33 |
| some_builder_global_settings | 1.98 |
| cron                         | 1.21 |
+------------------------------+------+

Qué significa: Una o dos opciones dominan. Es una buena noticia: puedes obtener grandes mejoras sin jugar al whack-a-mole.

Decisión: Para cada ofensor principal: decide borrar vs desactivar autoload vs dejar. Empieza con blobs de caché obvios y opciones residuales de plugins.

Task 4: Comprobar si una opción sospechosa es un transient (generalmente seguro purgar)

cr0x@server:~$ wp db query "SELECT option_name, autoload FROM wp_options WHERE option_name LIKE '\_transient\_%' LIMIT 5;"
+------------------------------+----------+
| option_name                  | autoload |
+------------------------------+----------+
| _transient_timeout_feed_123  | no       |
| _transient_feed_123          | no       |
| _transient_timeout_xxx       | no       |
| _transient_xxx               | no       |
| _transient_timeout_abc       | no       |
+------------------------------+----------+

Qué significa: La mayoría de los transients no se autoloadean, pero aún así hinchan la tabla y ralentizan escaneos/backs. Algunos plugins autoloadean transients por error o almacenan datos “similares a transients” sin el prefijo.

Decisión: Planea borrar transients expirados. Si hay muchos, automatiza la limpieza.

Task 5: Contar transients expirados (victoria barata)

cr0x@server:~$ wp db query "SELECT COUNT(*) AS expired FROM wp_options WHERE option_name LIKE '\_transient\_timeout\_%' AND option_value < UNIX_TIMESTAMP();"
+---------+
| expired |
+---------+
| 18742   |
+---------+

Qué significa: Tienes muchos transients expirados. WordPress no siempre los limpia agresivamente, y los plugins pueden ser descuidados.

Decisión: Bórralos (y sus pares) de forma controlada.

Task 6: Borrar transients expirados vía WP-CLI (relativamente seguro y reversible por regeneración)

cr0x@server:~$ wp transient delete --expired
Success: Deleted 18742 expired transients.

Qué significa: Eliminaste entradas de caché expiradas. Si algo se rompe, es un bug del plugin que dependía de datos expirados (sí, pasa).

Decisión: Revisa el tamaño de la tabla y el autoload. Si el rendimiento mejora, sigue adelante.

Task 7: Re-medir payload autoload después de limpiar transients

cr0x@server:~$ wp db query "SELECT ROUND(SUM(LENGTH(option_value))/1024/1024,2) AS autoload_mb FROM wp_options WHERE autoload='yes';"
+------------+
| autoload_mb|
+------------+
| 27.90      |
+------------+

Qué significa: Los transients no eran la causa principal; el grueso sigue siendo opciones autoloaded como blobs de caché.

Decisión: Apunta directamente a los principales ofensores.

Task 8: Hacer snapshot del valor de la opción antes de cambiarla (quieres rollback)

cr0x@server:~$ wp option get plugin_x_cache_blob --format=json | head -c 200
{"version":"4.2.1","generated_at":1735230932,"data":{"items":[{"id":1,"name":"..."}]}}

Qué significa: Puedes ver que es una estructura de caché generada, no un ajuste core. También huele a algo que podría moverse fuera de autoload.

Decisión: Guarda el valor completo en un archivo (o haz un backup de la BD) antes de tocarlo. Luego considera desactivar autoload primero, no borrar.

Task 9: Desactivar autoload para un blob de caché conocido (riesgo funcional mínimo)

cr0x@server:~$ wp db query "UPDATE wp_options SET autoload='no' WHERE option_name='plugin_x_cache_blob' LIMIT 1;"
Query OK, 1 row affected (0.02 sec)
Rows matched: 1  Changed: 1  Warnings: 0

Qué significa: Esa opción sigue existiendo; WordPress no la cargará automáticamente. El plugin la recuperará cuando la necesite.

Decisión: Prueba inmediatamente los flujos clave (página principal, checkout, login, admin). Si el plugin asumía autoload, lo sabrás rápido.

Task 10: Validar payload autoload tras des-autoloadear un gran ofensor

cr0x@server:~$ wp db query "SELECT ROUND(SUM(LENGTH(option_value))/1024/1024,2) AS autoload_mb FROM wp_options WHERE autoload='yes';"
+------------+
| autoload_mb|
+------------+
| 15.50      |
+------------+

Qué significa: Acabas de reducir casi a la mitad el payload autoload. Ese tipo de cambio se refleja en la latencia p95.

Decisión: Sigue con la lista de principales ofensores. Prefiere “autoload=no” sobre “DELETE” a menos que estés seguro.

Task 11: Encontrar opciones huérfanas de plugins desactivados (candidatos a limpieza)

cr0x@server:~$ wp plugin list --status=inactive
+----------------------+----------+-----------+---------+
| name                 | status   | update    | version |
+----------------------+----------+-----------+---------+
| old-gallery-plugin   | inactive | none      | 1.9.0   |
| legacy-seo-tool      | inactive | available | 2.3.1   |
+----------------------+----------+-----------+---------+

Qué significa: Los plugins inactivos con frecuencia dejan opciones atrás. Algunas son inofensivas. Otras son gigantes. Inactivo + grande + autoload=yes es un regalo.

Decisión: Busca prefijos de opción asociados con plugins inactivos y luego borra esas opciones tras hacer backup.

Task 12: Localizar opciones por patrón de nombre y tamaño antes de borrar

cr0x@server:~$ wp db query "SELECT option_name, autoload, ROUND(LENGTH(option_value)/1024/1024,2) AS mb FROM wp_options WHERE option_name LIKE 'old_gallery_%' ORDER BY LENGTH(option_value) DESC LIMIT 10;"
+---------------------------+----------+------+
| option_name               | autoload | mb   |
+---------------------------+----------+------+
| old_gallery_cache         | yes      | 3.70 |
| old_gallery_settings      | yes      | 0.05 |
+---------------------------+----------+------+

Qué significa: Esto probablemente es peso muerto si el plugin está inactivo y no piensas volver a activarlo.

Decisión: Exporta las filas y luego bórralas. Si tienes dudas, establece autoload=no primero y observa durante una semana.

Task 13: Hacer backup de filas específicas (rollback quirúrgico)

cr0x@server:~$ wp db query "SELECT * FROM wp_options WHERE option_name IN ('old_gallery_cache','old_gallery_settings')\G"
*************************** 1. row ***************************
option_id: 8812
option_name: old_gallery_cache
option_value: a:3:{s:7:"version";s:5:"1.9.0";...}
autoload: yes
*************************** 2. row ***************************
option_id: 8813
option_name: old_gallery_settings
option_value: a:2:{s:5:"theme";s:6:"light";...}
autoload: yes

Qué significa: Has capturado los valores exactos. Si la eliminación causa problemas, puedes reinsertarlos.

Decisión: Procede a borrar solo después de tener esta salida guardada o un snapshot de BD.

Task 14: Borrar opciones huérfanas conocidas (commit)

cr0x@server:~$ wp db query "DELETE FROM wp_options WHERE option_name IN ('old_gallery_cache','old_gallery_settings') LIMIT 2;"
Query OK, 2 rows affected (0.01 sec)

Qué significa: Las filas desaparecieron. Si el plugin está realmente sin uso, no hay impacto. Si aún se referenciaba, verás advertencias/errores rápidamente.

Decisión: Valida la funcionalidad del sitio; monitoriza logs de errores y consultas lentas.

Task 15: Inspeccionar tamaño de rewrite_rules (común, a veces legítimo)

cr0x@server:~$ wp option get rewrite_rules --format=json | head -c 120
{"^wp-json/?$":"index.php?rest_route=/","^product/(.+?)/?$":"index.php?product=$matches[1]","^..."}

Qué significa: rewrite_rules normalmente se autoloadea y puede crecer con rutas complejas (e-commerce, multilingüe, etc.). No lo desactives a ciegas; eso puede ralentizar el routing o causar comportamientos extraños.

Decisión: Si es enorme, probablemente tienes un plugin que genera reglas excesivas. Arregla la fuente, no solo el síntoma. Considera vaciar las reglas de forma segura durante mantenimiento.

Task 16: Vaciar rewrite rules (solo cuando sepas por qué)

cr0x@server:~$ wp rewrite flush --hard
Success: Rewrite rules flushed.

Qué significa: WordPress regeneró las rewrite rules. Esto puede reducir la opción si se acumularon reglas obsoletas, pero también puede regenerar el mismo tamaño si el generador sigue ruidoso.

Decisión: Si se reduce, genial. Si vuelve a crecer, busca el plugin/tema que añade demasiadas reglas.

Task 17: Comprobar si el object cache está habilitado (cambia el radio de daño)

cr0x@server:~$ wp plugin list --status=active | grep -E "redis|memcached|object"
redis-cache             active   none      2.5.3

Qué significa: Probablemente hay caching de objetos persistente. Eso ayuda, pero no excusa un payload autoload de 30 MB—especialmente durante flushes y expulsiones de caché.

Decisión: Sigue limpiando. También revisa tamaño de caché y políticas de expulsión para reducir rotación.

Task 18: Medir impacto a nivel de petición con una muestra TTFB antes/después

cr0x@server:~$ for i in {1..5}; do curl -s -o /dev/null -w "%{time_starttransfer}\n" https://example.com/; done
0.842
0.790
0.811
0.775
0.798

Qué significa: Esto no es un benchmark de laboratorio, pero detecta grandes mejoras. Repite después de los cambios (y tras limpiar cachés) para ver si las respuestas en frío mejoran.

Decisión: Si el TTFB baja significativamente y se mantiene estable, estás arreglando lo correcto. Si no, tu cuello de botella está en otra parte—continúa el diagnóstico (consultas lentas, CPU, PHP, llamadas externas).

Cambios seguros: qué puedes borrar frente a qué debes moderar

Tier 1: Usualmente seguro borrar (con backups)

  • Transients expirados: Están expirados. No deberían ser necesarios.
  • Opciones huérfanas de plugins: Para plugins que has eliminado o que nunca vas a reactivar.
  • Locks de cron antiguos: Si están atascados (manéjalo con cuidado), pero primero confirma que el sitio no está ejecutando un job.

Incluso lo “seguro” necesita backup. Borrar filas es permanente y eres una llamada de atención fatigada de guardia lejos de borrar el prefijo equivocado.

Tier 2: Prefiere cambiar autoload de yes → no

  • Caches generados almacenados como opciones: Si son grandes pero el plugin puede regenerarlos.
  • Grandes configuraciones de UI: Ajustes de widgets o builders que no se necesitan en cada petición del front-end.
  • Blobs de tipo analytics o logs: No deberían estar en options; pero desactivar autoload es un primer movimiento más seguro.

¿Por qué es esto más seguro? Porque los datos siguen ahí. Cambias “cuándo se cargan”, no “si existen”. La mayoría de plugins simplemente llamará a get_option() cuando lo necesiten y seguirán funcionando.

Tier 3: No tocar a la ligera

  • siteurl, home, active_plugins: autoexplicativo. Si rompes esto, te ganas un downtime.
  • cron: que sea grande es sospechoso, pero borrarlo puede eliminar jobs programados. Mejor arreglar lo que está llenando cron de eventos.
  • rewrite_rules: autoloaded por una razón; grande indica complejidad upstream.

Broma corta #2: Borrar active_plugins para acelerar WordPress es una optimización de rendimiento con el efecto secundario de “no hay sitio web”.

El objetivo real: reducir el “hotset” autoload

Pensá como ingeniero de caché. Autoload es un hotset: los datos que cargas en memoria temprano. El hotset debe ser pequeño, estable y realmente hot. Todo lo demás debe cargarse de forma perezosa o almacenarse correctamente (object cache, transient con TTL o una tabla dedicada).

Tres mini-historias del mundo corporativo desde las trincheras

Mini-historia 1: El incidente causado por una suposición equivocada

Un negocio de tamaño medio ejecutaba WordPress detrás de un proxy inverso y un CDN. El sitio parecía rápido en comprobaciones sintéticas porque la página principal siempre estaba en caché. La dirección concluyó que el origin no importaba mucho. Era “solo admin” lo que se sentía lento, y eso no aparecía en los dashboards.

Luego lanzaron una funcionalidad de membresía. Los usuarios autenticados eludían la mayoría del caching del CDN y el origin se volvió el producto. En el día del lanzamiento, el sitio no se cayó. Simplemente se convirtió en un desastre en cámara lenta: las páginas de perfil tardaban segundos; llamadas de checkout hacían timeout; los tickets de soporte llegaron antes que la plantilla del post-mortem.

La suposición equivocada fue sutil: “La base de datos está bien porque la CPU está baja.” En realidad, las opciones autoloaded habían crecido hasta convertirse en un payload de varios megabytes. Cada nuevo worker PHP en frío tenía que cargar todo, y cualquier pérdida de caché golpeaba la BD con una consulta gorda seguida de una gran deserialización.

La solución fue aburrida y efectiva: medir tamaño de autoload, desactivar autoload para las entradas de caché más grandes del plugin y borrar opciones huérfanas de dos plugins retirados. La mayor mejora no fue la latencia media; fue p95 y p99 durante ráfagas y despliegues. Dejaron de “sentirlo aleatorio” porque no lo era.

Mini-historia 2: La optimización que salió mal

Un equipo de marketing empresarial quería páginas más rápidas, así que añadieron un plugin que prometía “reducción de consultas a la BD”. Redujo el conteo de consultas—guardando datos computados agresivamente en una única opción y poniéndola en autoload. Los autores del plugin probablemente lo probaron en un sitio pequeño y declararon victoria.

En producción, la opción creció con cada variación de campaña y localización. El payload se infló. El conteo de consultas bajó. La huella de memoria subió. El time-to-first-byte empeoró, especialmente en flushes de caché tras despliegues.

La optimización salió mal porque se optimizó la métrica equivocada. El equipo celebró menos consultas en un panel de depuración mientras los clientes veían cargadores girando. En términos de operaciones: optimizaron el dashboard, no el sistema.

Eventualmente reemplazaron el enfoque “cache en opciones” del plugin por un object cache persistente y pusieron esa opción en autoload=no. El conteo de consultas subió ligeramente. La latencia bajó. Todos fingieron que ese era el plan original.

Mini-historia 3: La práctica aburrida pero correcta que salvó el día

Un grupo de servicios financieros ejecutaba WordPress como plataforma de contenidos adyacente a sistemas transaccionales. Su mayor miedo no era un post lento; era un incidente que distrajera al equipo on-call durante una caída real en otro sistema.

Implementaron dos prácticas mundanas: (1) un job semanal que registraba tamaño de autoload y top 20 de ofensores en una serie temporal, y (2) una regla de control de cambios que obliga a cualquier instalación de plugin a pasar una soak en staging con cheques de crecimiento de autoload.

Meses después, una actualización de plugin introdujo una nueva opción autoloaded que empezó a crecer rápidamente. La tendencia semanal la detectó antes de que fuera visible para usuarios. Revirtieron, abrieron ticket al proveedor y fijaron la versión. Sin llamada de incidente. Sin heroicos nocturnos. Solo una corrección silenciosa que nadie fuera de SRE supo.

Ese es el punto. El mejor incidente es el que nunca merece un canal de Slack.

Errores comunes: síntoma → causa raíz → solución

1) El admin está lento, el front-end “parece bien”

Síntoma: las páginas wp-admin se cuelgan; los editores se quejan; el front-end parece OK (gracias, CDN).

Causa raíz: El autoload bloat castiga el tráfico no cacheado y autenticado. Las páginas de admin también cargan más plugins y ajustes.

Solución: Mide MB de autoload; desactiva autoload para caches grandes de plugins; limpia opciones huérfanas. Valida con pruebas curl autenticadas o mediciones en navegador real.

2) Picos de latencia aleatorios tras despliegues o eventos de escalado

Síntoma: justo después de un despliegue o reinicio de pod, aparecen picos de latencia que luego se estabilizan.

Causa raíz: Workers en frío + object cache vacío significa que el payload autoload debe recuperarse y deserializarse repetidamente.

Solución: Reduce el payload autoload; asegura dimensionado del object cache; considera scripts de warm-up tras despliegues que toquen endpoints clave.

3) La CPU de la base de datos está baja pero las consultas “se sienten lentas”

Síntoma: sin saturación obvia de CPU DB; aún así lento.

Causa raíz: No todo el dolor es CPU. Valores grandes de opciones implican paquetes más grandes, más copias en memoria y sobrecarga de PHP al unserializar.

Solución: Reduce tamaño del payload; inspecciona principales ofensores; revisa memoria/CPU de workers PHP durante peticiones en frío.

4) Borraste una opción y un plugin “misteriosamente” se rompió

Síntoma: una funcionalidad desaparece; ajustes se resetean; errores fatales.

Causa raíz: Borraste estado que no era regenerable, o el autor del plugin asumía que la opción siempre existía.

Solución: Restaura desde backup; prefiere cambios a autoload=no primero; para borrados, elimina solo transients conocidos y opciones huérfanas confirmadas.

5) OPTIMIZE TABLE empeoró las cosas

Síntoma: picos de IO, lag de replicación o ralentizaciones durante “mantenimiento”.

Causa raíz: OPTIMIZE no aborda la semántica de autoload; puede reconstruir tablas y generar IO pesado, especialmente en datasets grandes.

Solución: No uses OPTIMIZE como primera línea. Reduce payload autoload y filas basura primero. Programa mantenimiento de tablas de forma deliberada y esporádica.

6) El tamaño de autoload baja, pero el rendimiento no mejora

Síntoma: redujiste autoload de 20 MB a 5 MB; los usuarios siguen quejándose.

Causa raíz: El cuello de botella está en otra parte: API externa lenta, sistema de archivos lento, CPU PHP saturada, índices faltantes en postmeta o pool de conexiones DB saturado.

Solución: Ejecuta slow query log; perfila PHP; revisa latencia de disco; valida salud del object cache; mide end-to-end con patrones de tráfico reales.

Listas de verificación / plan paso a paso

Fase 0: Redes de seguridad (haz esto antes de tocar datos)

  • Confirma el prefijo de tablas vía WP-CLI (Task 1).
  • Haz un snapshot o volcado de la base de datos (BD completa si es posible; al menos wp_options).
  • Tener un plan de rollback: restaurar dump o reinserción de filas guardadas.
  • Decide tu postura de mantenimiento: cambios en caliente con monitorización estrecha, o una ventana corta de mantenimiento.

Fase 1: Línea base y selección de objetivos

  • Mide MB de autoload (Task 2).
  • Lista los 20 principales autoloaded por tamaño (Task 3).
  • Clasifica cada opción top en: borrar, des-autoload, dejar.
  • Anota impacto y riesgo esperado para cada cambio. Si no puedes explicar qué es una opción, no la borres.

Fase 2: Limpieza de bajo riesgo (victorias que casi nunca dañan)

  • Borrar transients expirados (Tasks 5–6).
  • Eliminar opciones huérfanas de plugins que has quitado (Tasks 11–14).
  • Re-medir MB autoload y principales ofensores después de cada lote de cambios.

Fase 3: Ajustes de alto impacto (donde están las verdaderas ganancias)

  • Para cada opción gigante no core: establece autoload=no primero (Task 9).
  • Prueba rutas clave inmediatamente tras cada cambio (homepage, login, checkout, search, wp-admin).
  • Vigila logs de errores PHP y logs de aplicación en busca de avisos/warnings/fatales.
  • Solo borra opciones grandes cuando estés seguro de que pueden regenerarse o están verdaderamente huérfanas.

Fase 4: Verificar la mejora de la forma correcta

  • Mide estado final de MB de autoload.
  • Captura muestras TTFB antes/después (Task 18) y compara p95/p99 en tu APM si existe.
  • Simula un arranque en frío: reinicia PHP-FPM y limpia object cache en staging, luego vuelve a probar (no hacer esto a la ligera en prod).

Fase 5: Hacer que perdure

  • Añade monitorización de tamaño de autoload y principales ofensores.
  • Puerta de control para instalaciones/actualizaciones de plugins con chequeo de crecimiento de autoload en staging.
  • Educar: autoload no es un compactador de basura.

Prevención: evita que el autoload bloat vuelva

1) Trata las instalaciones de plugins como cambios de código

Si tu organización tiene un proceso de cambios para código pero no para plugins, felicitaciones: tus plugins son ahora código sin revisar. Muchos de los peores ofensores de autoload vienen de plugins que “cachean” metiendo arreglos enormes en options.

Política práctica: cada actualización de plugin pasa por staging donde registras MB de autoload antes y después de workflows típicos (guardar admin, importar productos, warm-up de caché). Si autoload crece materialmente, bloqueas o mitigás.

2) Prefiere caching de objetos persistente, pero que no oculte la pudrición

Redis/Memcached reduce golpes repetitivos a la BD. No hace que esté bien autoloadear 30 MB. Solo cambia cuándo pagas.

Lo que quieres es un hotset autoload pequeño más una caché para datos computados con TTL sensatos y comportamiento de expiración apropiado.

3) Pon límites de tamaño en tu playbook operativo

Decide un umbral que dispare acción. Para muchos sitios WordPress en producción, una línea de partida razonable es:

  • Avisar: autoload > 5 MB
  • Llamar a alguien (horario laboral): autoload > 10–15 MB
  • Criterio de incidente: autoload > 20 MB más picos de latencia correlacionados

4) Pregunta “esto debería estar en options?”

Algunos tipos de datos no pertenecen a options:

  • Logs (usa archivos, un servicio de logging o una tabla personalizada)
  • Índices computados grandes (usa transients con object cache o tablas personalizadas)
  • Estado por usuario/sesión (usa user meta, sesiones o almacenamiento dedicado)

5) Vigila crecimiento de cron y action scheduler

La opción cron puede crecer si se acumulan eventos o un plugin programa demasiados hooks. WooCommerce también tiene tablas de action scheduling (no en wp_options) que pueden necesitar su propio proyecto de limpieza. No los confundas; diagnostícalos por separado.

Preguntas frecuentes

1) ¿Qué tamaño deberían tener las opciones autoloaded?

Idealmente menos de 1 MB. Menos de 5 MB suele estar bien. Por encima de 10 MB normalmente vale la pena arreglarlo. Por encima de 20 MB es un riesgo de fiabilidad en arranques en frío.

2) ¿Deshabilitar autoload romperá mi sitio?

Puedes romperlo, pero generalmente es más seguro que borrar. Deshabilitar autoload significa que la opción sigue existiendo; el código puede recuperarla cuando la necesite. El riesgo son plugins que asumen incorrectamente que la opción está precargada. Mitiga cambiando una opción a la vez y probando flujos críticos.

3) ¿Es seguro borrar transients?

Los transients expirados son seguros de borrar en circunstancias normales. Los transients no expirados también suelen ser seguros (deberían regenearse), pero algunos plugins los usan mal como almacenamiento persistente. Si quieres riesgo mínimo, borra primero los expirados.

4) ¿Por qué rewrite_rules es tan grande?

Rutas complejas (productos, idiomas, custom post types) incrementan rewrite rules. Algunos plugins generan reglas excesivas o no limpian. Si es enorme, investiga qué está añadiendo rutas; vaciar las reglas puede ayudar temporalmente, pero arreglar el generador es la solución real.

5) ¿Necesito ejecutar OPTIMIZE TABLE después de la limpieza?

No automáticamente. InnoDB no siempre se beneficia como la gente espera, y OPTIMIZE puede ser disruptivo. Primero reduce los datos y observa el rendimiento. Si necesitas recuperar espacio en disco o desfragmentar significativamente, plánficalo deliberadamente.

6) Tengo Redis como object cache. ¿Por qué sigo preocupándome por autoload?

Porque las cachés fallan, reinician, expulsa y se limpian. El autoload bloat hace que esos eventos normales sean caros. Además, los datos autoloaded grandes aún deben deserializarse y procesarse en PHP.

7) ¿Y si la opción autoload más grande viene de un plugin imprescindible?

Pónla en autoload=no y prueba. Si el plugin sigue funcionando, ganaste. Si se rompe, tienes tres opciones: ajustar la configuración del plugin para reducir datos almacenados, reemplazar el plugin o aceptar el coste y mitigarlo con caching y capacidad.

8) ¿Cómo sé si una opción es segura de borrar?

Si es claramente una caché (a menudo nombrada cache, parecido a transient o incluye timestamps) y puede regenerarse, borrarla suele ser seguro. Si es configuración, claves de licencia o ajustes core, no la borres. Cuando tengas dudas: haz backup y primero pon autoload=no.

9) ¿El autoload bloat puede causar errores de memoria en PHP?

Sí. Los payloads autoload grandes aumentan el uso de memoria por petición, especialmente cuando hay copias múltiples durante unserialize/procesamiento. Si ves OOM kills o errores fatales de memoria en PHP correlacionados con pérdidas de caché, el tamaño de autoload es un sospechoso principal.

10) ¿Con qué frecuencia debería auditar wp_options?

Mensualmente para sitios estables, semanalmente para e-commerce activo o instalaciones con muchos plugins. Si despliegas o actualizas plugins frecuentemente, monitoriza continuamente y alerta sobre crecimiento.

Próximos pasos que puedes hacer hoy

Haz tres cosas, en este orden:

  1. Mide MB de autoload (Task 2) y apúntalo. Si no lo rastreas, no puedes detener regresiones.
  2. Toma el principal ofensor (Task 3) y pon autoload=no (Task 9). Prueba flujos críticos de inmediato.
  3. Limpia la basura fácil: transients expirados y opciones huérfanas de plugins (Tasks 5–6, 11–14).

Después de eso, trata el autoload como un presupuesto de rendimiento. Mantenlo pequeño. Mantenlo aburrido. Tu yo futuro—probablemente el que esté on-call a las 2 a.m.—te lo agradecerá.

← Anterior
Servidores Ubuntu 24.04: Snap vs apt — dónde Snap causa dolor silencioso (y qué hacer)
Siguiente →
WordPress 504 Gateway Timeout: ¿La base de datos o PHP? Cómo demostrarlo

Deja un comentario