Contents
Introducción
WP_Query es la clase central de WordPress para recuperar posts. En sitios con muchos contenidos o consultas complejas, una mala configuración puede provocar consultas SQL costosas (JOINs innecesarios, SQL_CALC_FOUND_ROWS, consultas que devuelven muchas filas). Dos parámetros sencillos —fields=ids y no_found_rows— permiten reducir drásticamente el coste de las consultas en muchos casos. Este artículo explica en detalle cómo y cuándo usarlos, riesgos, ejemplos prácticos y patrones avanzados para mantener un sitio WordPress ágil.
Qué hacen fields=ids y no_found_rows
- fields=ids: modifica la cláusula SELECT para devolver solo los IDs de los posts (SELECT ID FROM …). Menos datos transferidos y menos memoria usada por PHP al construir objetos completos.
- no_found_rows=true: evita que WP_Query calcule la cantidad total de resultados para paginación. Por defecto WordPress usa SQL_CALC_FOUND_ROWS o una consulta COUNT() adicional para saber cuántos posts existen en total si no necesitas ese número (por ejemplo, en consultas para listados internos o procesamiento por lotes) puedes omitirlo.
Beneficios principales
- Menor tiempo de ejecución de la consulta.
- Menos uso de memoria y CPU en PHP porque no se crean objetos WP_Post completos.
- Menos I/O en la base de datos al transferir menos columnas.
- Si combinamos con update_post_meta_cache y update_post_term_cache desactivados, evitamos cargas adicionales en caché.
Limitaciones y cuándo no usarlos
- Paginación visible al usuario: si necesitas mostrar páginas con número total de resultados o enlaces de paginación que muestren el número de páginas, no_found_rows=true romperá esa funcionalidad a menos que calcules el total por separado.
- Si necesitas campos del post (title, content, meta) inmediatamente, fields=ids obliga a ejecutar consultas adicionales para obtener esos datos.
- Consultas que dependen del orden por campos que no sean ID pueden requerir cuidado: al solicitar sólo IDs, conviene asegurar que la cláusula ORDER BY devuelva el orden esperado.
Patrones y buenas prácticas
- Si solo necesitas IDs para procesar en background (reindexar, enviar emails, regenerar thumbnails), usa fields=ids y no_found_rows=true.
- Para listados públicos paginados, evita no_found_rows=true o calcula el total con una consulta COUNT() separada.
- Desactiva caches automáticos si no los necesitas: update_post_meta_cache y update_post_term_cache cuando solo trabajas con IDs.
- Usa transients o un object cache para almacenar resultados de consultas pesadas (IDs) si se repiten con frecuencia.
- Evita meta_query pesadas con comparaciones LIKE sobre campos no indexados si es posible, crea índices o normaliza datos a taxonomías.
Ejemplos prácticos
1) Consulta básica y eficiente para procesamiento en background
Recuperar IDs y procesarlos en lotes sin cargar meta/terms automáticamente:
args = array(
post_type => post,
posts_per_page => 100,
fields => ids, // solo IDs
no_found_rows => true, // no calcula total
update_post_meta_cache => false, // no cargar meta innecesario
update_post_term_cache => false, // no cargar taxonomías
meta_query => array(
array(
key => _mi_meta,
value => valor,
),
),
)
query = new WP_Query(args)
foreach (query->posts as post_id) {
// procesar por ID: wp_update_post, wp_delete_post, etc.
}
2) Preservar orden cuando necesitas luego los objetos completos
Patrón: pedir IDs ordenados, después recuperar objetos en el mismo orden con post__in y orden por el orden de post__in.
// 1) Obtener IDs ordenados eficientemente
id_args = array(
post_type => product,
posts_per_page => 50,
fields => ids,
orderby => date,
order => DESC,
no_found_rows => true,
)
id_query = new WP_Query(id_args)
ids = id_query->posts
if (!empty(ids)) {
// 2) Recuperar objetos completos en el mismo orden
posts = get_posts(array(
post__in => ids,
posts_per_page => count(ids),
orderby => post__in, // respeta el orden de ids
update_post_meta_cache => true, // si necesitas meta
update_post_term_cache => true, // si necesitas taxonomías
))
// posts ahora en el mismo orden que ids
}
3) Implementar paginación con conteo por separado
Si necesitas paginación y quieres aun así reducir tamaño de SELECT en la consulta principal, puedes obtener los IDs para la página y calcular el total con una consulta COUNT separada (óptimo cuando la COUNT es mucho más barata que SQL_CALC_FOUND_ROWS en la misma consulta).
global wpdb
paged = max(1, get_query_var(paged))
per_page = 20
offset = (paged - 1) per_page
// 1) Consulta principal: traer solo IDs de la página
page_ids = wpdb->get_col(wpdb->prepare(
SELECT ID
FROM {wpdb->posts}
WHERE post_type = %s
AND post_status = publish
ORDER BY post_date DESC
LIMIT %d, %d
, post, offset, per_page))
// 2) Conteo total separado (más rápido en algunas configuraciones)
total = (int) wpdb->get_var(wpdb->prepare(
SELECT COUNT(ID)
FROM {wpdb->posts}
WHERE post_type = %s
AND post_status = publish
, post))
total_pages = ceil(total / per_page)
// 3) Recuperar objetos si hace falta
if (!empty(page_ids)) {
posts = get_posts(array(
post__in => page_ids,
orderby => post__in,
posts_per_page => count(page_ids),
))
}
4) Uso en trabajos CRON o batch con límites grandes
Cuando iteras sobre muchos posts, evita cargar todos a la vez usa fields=ids y procesado por lotes para mantener la memoria baja.
per_batch = 500
offset = 0
while (true) {
q = new WP_Query(array(
post_type => post,
posts_per_page => per_batch,
fields => ids,
no_found_rows => true,
offset => offset,
update_post_meta_cache => false,
update_post_term_cache => false,
))
if (empty(q->posts)) {
break
}
foreach (q->posts as post_id) {
// procesar
}
wp_cache_flush() // opcional: liberar memoria del object cache si es necesario
offset = per_batch
}
Consideraciones sobre performance SQL
- SQL_CALC_FOUND_ROWS puede ser costoso en tablas grandes. En muchas configuraciones es más eficiente ejecutar una consulta COUNT separada con índices adecuados.
- fields=ids reduce ancho de banda y CPU al evitar selección de columnas pesadas (post_content, post_title, post_excerpt) y reduce tiempo de serialización/deserialización en PHP.
- Desactivar caches automáticos evita llamadas adicionales a WPs cache warming. Reactiva solo si realmente necesitas meta/terms en la fase inmediata.
Errores comunes
- Usar no_found_rows=true y luego confiar en wp_query->max_num_pages o wp_query->found_posts: esos valores no reflejarán el total correcto.
- Pensar que fields=ids evita JOINs generados por meta_query o tax_query: los JOINs todavía pueden ocurrir fields=ids solo cambia SELECT, no la estructura de la cláusula FROM/JOIN/WHERE.
- Solicitar posts_per_page=-1 con fields=ids en tablas gigantes sin paginar: puedes obtener decenas de miles de IDs y aún así saturar memoria o tiempo de ejecución. Mejor procesar por lotes.
Resumen de configuración recomendada
| Situación | Parámetros recomendados |
| Proceso en background / reindexar | fields=ids, no_found_rows=true, update_post_meta_cache=false, update_post_term_cache=false |
| Listado público paginado | no_found_rows=false (por defecto) — o calcular COUNT por separado si quieres optimizar |
| Recuperar objetos tras filtrar IDs | Primero fields=ids (con orden deseado), luego get_posts con post__in y orderby=post__in |
Conclusión
fields=ids y no_found_rows son herramientas potentes para optimizar consultas WP_Query cuando necesitamos eficiencia y no todos los datos del post ni el total de resultados. Usados correctamente (por ejemplo en trabajos en background, APIs internas y procesado por lotes) reducen considerablemente el tiempo de consulta y el consumo de recursos. Sin embargo, hay que ser cuidadoso con la paginación visible y con consultas que requieren meta o taxonomías: en esos casos conviene combinar estrategias (consulta de IDs recuperación ordenada de objetos, o conteo separado con COUNT) para obtener un equilibrio entre rendimiento y funcionalidad.
|
|
Acepto donaciones de BAT's mediante el navegador Brave 🙂 |
