Seguramente es otro de esos posts nerdada pero que me generó mucha curiosidad cuando tuve que resolver el problema.
La cuestión es así, un servidor de un amigo que tiene un Wordpress con muchas visitas, entre los famosos plugins de WP hay uno que usan muchos que se llama Yoast SEO que básicamente se encarga de administrar el SEO de cada artículo y componente del sitio.
El plugin funciona muy bien y ayuda a las visitas pero tiene un problemita: jamás fue pensado para un sitio enorme...
Aviso que encontrar esto me llevó un buen rato, por suerte el servidor donde corre el sitio es un VPS con un Ubuntu más o menos bien instalado por quien escribe que tiene acceso a configuraciones extra y logs.
Hace ya tiempo le había configurado en el MySQL el log de Slow Query que sirve para ver cuales de las consultas se está tardando más de la cuenta. Llegué a una en particular que identificaba a Yoast como el principal sospechoso:
SELECT COUNT(P.ID) FROM wp_posts AS P LEFT JOIN wp_yoast_indexable AS I ON P.ID = I.object_id AND I.link_count IS NOT NULL AND I.object_type = 'post' LEFT JOIN wp_yoast_seo_links AS L ON L.post_id = P.ID AND L.target_indexable_id IS NULL AND L.type = 'internal' AND L.target_post_id IS NOT NULL AND L.target_post_id != 0 WHERE ( I.object_id IS NULL OR L.post_id IS NOT NULL ) AND P.post_status = 'publish' AND P.post_type IN ('post', 'page', 'attachment', 'wpzoom');Aquí vemos un lindo query en el que sólo quiere contar la cantidad de elementos, un inocente COUNT(P.ID) ¿no? pero miren bien, si no son expertos de SQL (yo no lo soy, sólo un amateur más) hay algo evidente que indica que todo fallará: LEFT JOIN.
El LEFT JOIN es un arma de doble filo, los DBA odian que los DEVs los usemos, tienen razón, son una violación permanente de recursos.
Pero, por si hay un DBA en la sala, démosle algunos números para que vea la enormidad de la consulta.
La tabla wp_posts tiene 132.000 registros aproximadamente, un buen sitio, uno de los grandecitos, pero ¿Y las tablas de Yoast?
En estas se indican materiales que pueden ser indexables y links de cada nota, el plugin te "exige" que para que una nota esté bien de SEO apunte a, al menos, una url externa, una interna y cosas así, todo eso lo va registrando.
En wp_yoast_indexable había 152.000 registros y en wp_yoast_seo_links unos 134.000, es decir, el LEFT JOIN (a groso modo, no exactamente como digo pero para dar una idea) multiplica una cosa con la otra en una gran matriz para poder encontrar los casos en los que sí y en los que no hubo coincidencia. A diferencia del JOIN que sólo cuando hay un acierto se cruza, en el LEFT entra todo.
132k * 152k * 134k = 2.688.576.000 millones, imposible, no? Okey, esto sería si se cruzaran todos con todos y sin índices, aquí por suerte hay algunos, aun así el resultado es una barbaridad enorme de memoria y disco swapeando con el procesador esperando y la tabla wp_posts bloqueada.
BLOQUEADA? No es acaso la tabla principal donde están todas las notas de un sitio? Así es, todos los demás queries se quedaban esperando la liberación, ni hablar si tenían que escribir en las otras dos, así que el sitio arrancaba bien en cada reiniciada de servidor hasta que este query entraba en la cola y chau, adiós servidor.
Ahora bien, estamos hablando de un plugin que utilizan MILLONES de sitios para mejorar su SEO, si te va muy bien empezás a consumir recursos como un desgraciado y no entendés por qué. PORQUE ESTÁ MAL PROGRAMADO!
No encontré a ningún otro quejándose de esto, será que en el primer mundo es barato contratar un VPS cada vez más grande pero en mi caso tuve que limpiar de un sopapo la tabla wp_yoast_seo_links y liberé el CPU. ¿Lo ideal? Cambiar a otro plugin, ahora estoy probando Rank Math SEO a sugerencia de Martín Aberastegue que me dijo que andaba bien y permitía la importación de lo que tengas en YOAST.
PS: por suerte en este blog no uso Wordpress :P ah, eso sí, el SEO del sitio apesta, pero bueno