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 🙂 |