Pulsa ESC para cerrar

Curso WordpressCurso Wordpress

Cómo encontrar las consultas SQL que hacen lento tu WordPress (y arreglarlas)

Tienes caché, imágenes optimizadas y un buen hosting, pero ciertas páginas siguen tardando: el buscador, el listado de productos con filtros, el escritorio. Cuando la lentitud aparece solo en algunas pantallas, casi siempre el culpable es una consulta a la base de datos.

La buena noticia es que esas consultas se pueden encontrar con nombre y apellido: qué consulta es, cuánto tarda y qué plugin la hizo.

Nivel 1: Query Monitor (para todos)

Instala el plugin gratuito Query Monitor. Agrega un menú en la barra de administración que muestra, en cada página que visitas como administrador:

  • Cuántas consultas se hicieron y cuánto tardaron en total.
  • Consultas lentas, marcadas en rojo.
  • Consultas duplicadas: la misma consulta repetida muchas veces, típico de un plugin mal hecho.
  • Por componente: cuánto tiempo de base de datos consume cada plugin y el tema.

Abre la página lenta, despliega Query Monitor y ve a Consultas por componente. Si un plugin se lleva el 80 % del tiempo, ya sabes por dónde empezar.

Query Monitor solo se muestra a administradores, así que puedes usarlo en un sitio en producción. Aun así, desactívalo cuando termines: también consume recursos.

Nivel 2: un registro de consultas lentas hecho por ti

Query Monitor solo ve lo que tú visitas. Si la lentitud aparece en horas punta o con clientes, necesitas registrar lo que pasa con todos. Este mu-plugin guarda en un archivo cada consulta que supere el umbral que elijas.

Primero, activa temporalmente el registro de consultas en wp-config.php:

define( 'SAVEQUERIES', true );

Luego crea wp-content/mu-plugins/cwp-consultas-lentas.php:

<?php
/**
 * Plugin Name: Registro de consultas lentas (Curso WordPress)
 * Description: Anota en wp-content/consultas-lentas.log las consultas de más de 0,2 s.
 */

const CWP_UMBRAL_SEGUNDOS = 0.2;

add_action( 'shutdown', function () {
	global $wpdb;
	if ( ! defined( 'SAVEQUERIES' ) || ! SAVEQUERIES || empty( $wpdb->queries ) ) {
		return;
	}
	$url = isset( $_SERVER['REQUEST_URI'] ) ? $_SERVER['REQUEST_URI'] : 'cli';
	foreach ( $wpdb->queries as $q ) {
		list( $sql, $tiempo, $origen ) = $q;
		if ( $tiempo < CWP_UMBRAL_SEGUNDOS ) {
			continue;
		}
		$linea = sprintf(
			"[%s] %.3fs %s\n  SQL: %s\n  Origen: %s\n",
			gmdate( 'Y-m-d H:i:s' ),
			$tiempo,
			$url,
			preg_replace( '/\s+/', ' ', $sql ),
			$origen
		);
		error_log( $linea, 3, WP_CONTENT_DIR . '/consultas-lentas.log' );
	}
} );

Déjalo funcionando unas horas en un momento de tráfico normal y revisa el archivo. La línea Origen muestra la cadena de funciones que llamó a la consulta, y ahí aparece el nombre del plugin o del archivo del tema.

Esto es temporal. SAVEQUERIES guarda todas las consultas en memoria y vuelve el sitio algo más lento. Cuando termines, quita la constante, borra el mu-plugin y borra el archivo .log, que además no debe quedar a la vista de nadie.

Nivel 3: el registro de MySQL en tu VPS

Si administras tu propio servidor con cPanel/WHM, MySQL o MariaDB pueden registrar las consultas lentas de todos los sitios del servidor. Por SSH como root, agrega a /etc/my.cnf, dentro de la sección [mysqld]:

slow_query_log = 1
slow_query_log_file = /var/lib/mysql/consultas-lentas.log
long_query_time = 1

Reinicia el servicio y, después de unas horas, pide un resumen agrupado:

/scripts/restartsrv_mysql

# Las 10 consultas que más tiempo total consumieron
mysqldumpslow -s t -t 10 /var/lib/mysql/consultas-lentas.log

Para entender por qué una consulta es lenta, ejecútala en phpMyAdmin con EXPLAIN delante. Si en la columna rows ves cientos de miles y en key dice NULL, MySQL está leyendo la tabla entera porque no tiene un índice que le sirva.

Los 6 culpables que más se repiten

  1. Búsquedas en campos personalizados con LIKE '%texto%'. La tabla wp_postmeta no tiene índice sobre los valores. Si un filtro de productos busca así, cada búsqueda recorre la tabla completa. Solución: usar taxonomías en vez de campos para todo lo que se filtra (color, talla, marca).
  2. orderby => 'rand'. Ordenar al azar obliga a MySQL a leer todo. Mejor elige al azar en PHP entre unos pocos IDs.
  3. posts_per_page => -1. «Traer todo» funciona con 50 entradas y revienta con 50.000. Pagina siempre.
  4. Contar el total sin necesitarlo. Si no muestras paginación, agrega 'no_found_rows' => true a tu consulta.
  5. Opciones autoload gigantes. No es una consulta lenta, pero pesa en todas. Revisa la tabla wp_options.
  6. Tablas sin los índices adecuados. El plugin gratuito Index WP MySQL For Speed agrega índices mejores a las tablas de WordPress. Haz respaldo antes.

Un ejemplo de consulta bien escrita para un listado que no necesita paginación:

$consulta = new WP_Query( array(
	'post_type'              => 'product',
	'posts_per_page'         => 12,
	'no_found_rows'          => true,  // no calcula el total de páginas
	'fields'                 => 'ids', // solo IDs si no necesitas todo el objeto
	'update_post_term_cache' => false, // no carga categorías si no las muestras
) );

¿Encontraste una consulta lenta y no sabes cómo arreglarla? Pégala en el foro junto con el resultado de EXPLAIN y la revisamos entre todos.