Cómo optimizar un sitio WordPress para millones de entradas
Estoy trabajando en un sitio web para una empresa que probablemente creará millones de entradas mediante un tipo de contenido personalizado. Son oraciones, básicamente el usuario en el frontend envía una frase corta a través de un formulario. A la empresa solo le interesa el contenido de la entrada y la fecha de publicación. El sitio ni siquiera se ha lanzado y ya tienen más de 120,000 entradas, así que hablo muy en serio cuando digo millones.
Entonces, algunas preguntas sobre optimización:
- Supongamos que tengo una categoría 'destacado' en un tipo de contenido personalizado que tiene 500,000 entradas. La categoría destacada solo tiene 500 entradas. Si creo una consulta para las entradas destacadas, ¿estoy consultando las 500,000 entradas completas, o solo las 500 destacadas? ¿Qué pasa si solo quiero mostrar las diez entradas más recientes que están destacadas?
- Al guardar este tipo de contenido personalizado en la base de datos, ¿hay algo que pueda hacer para reducir los recursos del servidor, especialmente porque lo único que realmente se necesita es el contenido de la entrada y la fecha?
- ¿Debería siquiera estar usando un tipo de contenido personalizado? Me gusta en principio porque está bien integrado en el panel de administración de WordPress, pero si hay desventajas significativas en el rendimiento, supongo que puedo hacer algo diferente.
Nunca he trabajado en un proyecto de esta escala, así que estoy un poco más preocupado por el rendimiento de lo habitual. ¡Gracias por cualquier ayuda!

1. Establecer la consulta antes de que se ejecute WP_Query
Esto parece ser lo más importante a tener en cuenta al intentar minimizar las consultas a la base de datos, ya que la única oportunidad de modificar la consulta es, por supuesto, antes de que se ejecute en la base de datos SQL.
Consultas normales
Para una consulta normal, WordPress utiliza la función wp()
, que a su vez llama a $wp->main( $query_vars )
. Las variables "is_" de las etiquetas condicionales se establecen antes de pasarlas a WP_Query->get_posts()
, que las convierte en una consulta de base de datos MySQL y finalmente las almacena en el objeto $wp_query. Es posible filtrar la consulta antes de que realmente se ejecute en la base de datos SQL.
El gancho de acción pre_get_posts
se conecta a este proceso, permitiéndote cambiar la consulta antes de que se pase a WP_Query->get_posts()
.
Por ejemplo, si deseas filtrar la consulta para publicaciones en la categoría "destacados", usarías add_action( 'pre_get_posts', 'tu_nombre_de_funcion' );
e incluirías la etiqueta condicional in_category
dentro de tu_nombre_de_funcion
.
function tu_nombre_de_funcion( $query ) {
if ( $query->in_category( 'destacados' ) && $query->is_main_query() ) {
// Reemplaza 123 con el ID de la categoría destacada.
$query->set( 'cat', '123' );
}
}
add_action( 'pre_get_posts', 'tu_nombre_de_funcion' );
Ver Referencia de Acción de la API de Plugins/pre get posts « WordPress Codex
Solicitudes de página
En cuanto a las plantillas de página, como la página de archivo para la categoría "destacados", las etiquetas condicionales no funcionarán desde el filtro pre_get_posts
. Por ejemplo, no puedes usar is_category
para verificar la página de archivo porque WP_Query no se ha ejecutado.
En su lugar, tendrías que modificar la consulta principal para las solicitudes de página con un new WP_Query
que se vería algo como $query = new WP_Query( 'cat=123' );
. Esto ejecuta la consulta con el argumento apropiado establecido desde el principio.
Ver Referencia de Clase/WP Query « WordPress Codex
2. Guardar en la base de datos
Puedes usar el filtro wp_insert_post_data
asegurando que solo los $data relevantes para tu tipo de publicación personalizado se devuelvan a wp_insert_post
. Asegúrate de incluir una declaración condicional para verificar tu tipo de publicación personalizado.
Referencia de Filtro de la API de Plugins/wp insert post data « WordPress Codex
Este gancho es llamado por la función wp_insert_post
, que es llamada por wp_update_post cuando actualizas tu tipo de publicación personalizado, generalmente al guardar un borrador o publicar la entrada.
Tendrás que hacer pruebas de rendimiento tú mismo, ya que no puedo hablar personalmente sobre la importancia de la optimización de reducir los datos que se actualizan en la base de datos.
3. ¿Los tipos de publicaciones personalizados afectan el rendimiento?
En mi experiencia, los tipos de publicaciones personalizados son una herramienta poderosa para gestionar contenido. No conozco otra forma de gestionar publicaciones de todas las maneras que permite de una forma que use menos recursos. Personalmente, me enfocaría en encontrar formas de reducir el número de consultas realizadas siempre que sea posible.
Solía haber un problema de rendimiento relacionado con la estructura de enlaces permanentes que hacía que el rendimiento se viera afectado cuando comenzaba con texto en lugar de un número.3 Esto era particularmente problemático para sitios con un gran número de páginas, pero se solucionó desde la versión 3.3 de WordPress.
Solo menciono los enlaces permanentes aquí porque el slug suele ser la primera parte de la estructura de enlaces permanentes que puede o no haber afectado el rendimiento antes de la versión 3.3. Aparte de eso, no estoy al tanto de ningún problema de rendimiento que surja del uso de tipos de publicaciones personalizados.
Otras opciones de rendimiento
Transients
Esto no es un reemplazo para mantener las consultas al mínimo en tu código, pero puedes usar set_transient para almacenar las consultas durante algún tiempo para que no sean necesarias nuevas consultas. Aquí está el ejemplo utilizado en la publicación de Dave Clements. También, ten en cuenta que recomienda agregar una acción save_post
para eliminar el transient cada vez que se actualiza un tipo de publicación determinado.
<?php // CONSULTA EN EL FOCO
if( false === ( $its_query = get_transient( 'its_query' ) ) ) {
$pttimestamp = time() + get_option('gmt_offset') * 60*60;
$its_query = new WP_Query( array(
'post_type' => 'spotlight',
'posts_per_page' => 1,
'post__not_in' => $do_not_duplicate,
'meta_query' => array(
array(
'key' => '_hpc_spotlight_end_time',
'value' => $pttimestamp,
'compare' => '>'
)
)
) );
set_transient( 'its_query', $its_query, 60*60*4 );
}
if( have_posts() ) { // OCULTAR SECCIÓN SI NO HAY FUNCIONALIDAD ACTUAL DE ITS ?>
// EL BUCLE VA AQUÍ: NO ES IMPORTANTE PARA EL EJEMPLO
<?php } ?>
Más optimización de consultas
Thomas Griffin tiene algunos buenos consejos en su tutorial Optimizar consultas de WordPress. Aquí hay una breve lista de sus sugerencias:
Establecer
'cache_results' => false
en consultas únicas si tu servidor no usa caché persistente como Memcached. Las consultas únicas se describen como "consultas que se usan para mostrar pequeñas cantidades de datos. Podría ser que solo quieras mostrar títulos de publicaciones relacionados con la publicación actual, o que quieras mostrar un menú desplegable de publicaciones para seleccionar una configuración de opción particular."Su ejemplo:
$query = get_posts( array( 'posts_per_page' => 1, 'cache_results' => false ) );
Establecer
'no_found_rows' => true
donde no se necesita paginación. Esto "evitará que MySQL cuente los resultados para ver si necesitamos paginación o no."Su ejemplo:
$query = new WP_Query( array( 'posts_per_page' => 1, 'no_found_rows' => true ) );
Consultar solo IDs de publicaciones si es todo lo que necesitas
'fields' => 'ids'
enget_posts
. Esto debería reducir significativamente la cantidad de datos devueltos, que es bastante por publicación si miras Descripción de la base de datos « WordPress CodexSu ejemplo:
$query = get_posts( array( 'posts_per_page' => 1, 'fields' => 'ids' ) );
Además de ese último consejo, el mismo razonamiento se puede aplicar cuando solo necesitas uno o unos pocos campos de publicación usando get_post_field.
Tener una comprensión sólida de cómo funciona la consulta es esencial. Cuanto más específico puedas ser con tus consultas, menos trabajo estarás demandando de tu base de datos SQL. Esto significa que hay un vasto número de posibilidades para gestionar consultas a la base de datos. Ten cuidado con las consultas personalizadas en cuanto a dónde se ejecutan (¿es una página de administración?), usa una adecuada saneamiento en consultas directas e intenta usar funciones nativas de WordPress donde te permita lograr el mismo rendimiento.

El tema está completamente construido a medida, así que literalmente solo estamos consultando los elementos absolutamente esenciales. Sin embargo, estos son extremadamente útiles. Dado esto, voy a revisar y hacer algunos cambios en mis consultas. ;)

Agregaría que deberías evitar las consultas meta siempre que sea posible. Ciertamente no ejecutes una consulta contra dos campos meta simultáneamente. Esto resulta en consultas dobles y triples que rápidamente se convierten en una pesadilla de rendimiento. Los tipos de posts personalizados a menudo pueden ayudar con esto.

También agrego:
'no_found_rows' => true,
'update_post_term_cache' => false,
'update_post_meta_cache' => false,
'cache_results' => false
- no_found_rows (booleano) – configúralo como true cuando no necesites paginación ni el conteo del número total de posts encontrados.
- cache_results (booleano) – Cache de información de posts.
- update_post_meta_cache (booleano) – Cache de metainformación de posts.
- update_post_term_cache (booleano) – Cache de información de términos de posts.
Al usar estos parámetros y pasar valores como FALSE, podemos hacer que la consulta sea más rápida al evitar que se ejecuten algunas consultas adicionales a la base de datos.
Nota: No deberíamos usar estos parámetros siempre, ya que agregar cosas al caché es lo correcto. Sin embargo, pueden ser útiles en circunstancias específicas y deberías considerar usarlos cuando sepas lo que estás haciendo.
Por favor visita: https://drujoopress.wordpress.com/2013/06/27/how-to-optimize-wordpress-query-to-get-results-faster/#more-184

Por favor, [edita] tu respuesta y agrega una explicación: ¿por qué eso podría resolver el problema?

No puedo agregar mi comentario en esta respuesta: https://wordpress.stackexchange.com/a/166699/57674

Como todas las preguntas sobre optimización prematura, esta no puede responderse realmente sin conocer los patrones de uso exactos, que muchas veces solo se descubren cuando el sistema está en producción.
En general, según las especificaciones de MYSQL, no debería haber ningún problema con la cantidad de datos. Por supuesto, buscar datos incluso con los mejores algoritmos será más lento que con tablas mucho más pequeñas, pero la solución para eso es simple: una CPU más potente.
Podrías considerar optimizar cómo se almacenan los metadatos (por ejemplo, no almacenar datos relacionados con ping), pero este tipo de cosas depende de lo que hagas exactamente, y al final podrías necesitar una CPU más potente de todos modos, por lo que podría no valer la pena el esfuerzo.
