Como corrigir queries lentas no banco com JetEngine e ACF PRO no WordPress
O que é queries lentas do JetEngine e ACF PRO no banco?
As queries lentas do JetEngine e ACF PRO no banco são consultas SQL que demoram para retornar porque dependem da tabela wp_postmeta. Tanto o ACF PRO quanto o JetEngine, na configuração padrão, gravam cada campo personalizado como uma linha em wp_postmeta (pares meta_key e meta_value). Quando um JetEngine Listing Grid filtra ou ordena por esses campos, o WordPress monta uma WP_Meta_Query que faz um JOIN em wp_postmeta para cada condicao. A coluna meta_value e do tipo LONGTEXT e não tem indice útil, entao o MySQL varre muitas linhas para resolver o filtro, e o tempo de resposta cresce com o tamanho da tabela.
Em sites com muitos posts e muitos campos por post, a wp_postmeta passa de centenas de milhares de linhas e cada listagem vira uma consulta cara. O resultado e TTFB alto, picos de CPU no banco e timeouts em páginas de arquivo, busca e filtros AJAX. A documentação de performance do WordPress reforça que ler dados do banco a cada carregamento, sem um cache de objeto persistente, sobrecarrega o servidor de banco em horarios de pico. Resolver passa por medir a query real, reduzir o peso da meta_query e mover dados de grande volume do wp_postmeta para uma estrutura própria, como os Custom Content Types do JetEngine.
Como identificar
- Páginas com JetEngine Listing Grid demoram vários segundos para carregar e o TTFB sobe em arquivos, busca e filtros.
- O filtro AJAX do JetSmartFilters trava ou retorna com atraso ao combinar mais de um campo do ACF ou do JetEngine.
- O log de consultas lentas (slow query log) registra SELECT com vários JOIN na tabela wp_postmeta e clausula meta_value.
- O Query Monitor mostra uma única query de listagem consumindo a maior parte do tempo total da página.
- O uso de CPU do MySQL dispara e aparecem timeouts ou erro ‘MySQL server has gone away’ em horarios de pico de acesso.
Como prevenir
- Planeje desde o inicio onde cada dado mora: campos pontuais por post como meta do ACF ou JetEngine, e dados de alto volume em Custom Content Types do JetEngine, que gravam em tabela própria.
- Sempre ative paginação ou lazy load nos Listing Grids e limite os itens por página, evitando consultas que retornam milhares de linhas em um único request.
- Mantenha um cache de objeto persistente (Redis ou Memcached) ativo em producao para servir consultas repetidas da memória, conforme recomenda a documentação de performance do WordPress.
- Monitore o crescimento da wp_postmeta e o slow query log periodicamente, para detectar meta_query pesadas antes de virarem gargalo em horario de pico.
Causa
- Os campos do ACF PRO e do JetEngine são gravados como meta em wp_postmeta, e o Listing Grid filtra ou ordena por eles, gerando uma WP_Meta_Query com um JOIN em wp_postmeta para cada condicao do filtro.
- A coluna meta_value de wp_postmeta e LONGTEXT e não possui indice por valor, entao filtros do tipo meta_value LIKE ou comparacoes numericas forçam o MySQL a varrer a tabela inteira em vez de usar indice.
- O JetEngine Listing Grid esta configurado para trazer todos os posts de uma vez (sem paginação ou lazy load), montando uma consulta que retorna e ordena milhares de linhas em um único request.
- Dados de alto volume (catalogos, diretorios, relacionamentos) estão armazenados como meta de post em vez dos Custom Content Types do JetEngine, que gravam em tabela própria, inchando o wp_postmeta para centenas de milhares de linhas.
- Não ha cache de objeto persistente (Redis ou Memcached) ativo, entao a mesma consulta de listagem e refeita no banco a cada carregamento, em vez de ser servida da memória, sobrecarregando o MySQL nos picos de tráfego.
Como resolver
- Identifique a query lenta com o Query Monitor: Instale o plugin Query Monitor e abra a página lenta logado como administrador. No painel Database Queries, ordene por tempo e localize a consulta de listagem com vários JOIN em wp_postmeta. Anote o tempo, a tabela e as clausulas meta_key envolvidas antes de mudar qualquer coisa.
Painel WP -> Plugins -> Adicionar novo -> instale e ative o Query Monitor Abra a página lenta e clique no menu do Query Monitor na barra superior Va em Queries -> Database Queries e ordene a coluna de tempo do maior para o menor - Ative o slow query log do MySQL para confirmar o gargalo: Habilite o log de consultas lentas no MySQL para capturar as queries que passam do limite de tempo. Isso confirma se o gargalo e a meta_query sobre wp_postmeta e da a consulta exata para otimizar. Em hospedagem gerenciada, ative pelo painel ou pelo suporte.
SET GLOBAL slow_query_log = 'ON'; SET GLOBAL long_query_time = 1; SET GLOBAL slow_query_log_file = '/var/log/mysql/slow.log'; EXPLAIN SELECT ... -- rode EXPLAIN na query capturada para ver os JOIN em wp_postmeta - Reduza o peso do Listing Grid e do filtro: No JetEngine, edite o Listing Grid e ative a paginação ou o lazy load para não trazer todos os posts de uma vez, e limite o número de itens por página. Reduza também a quantidade de campos meta usados como filtro e ordenacao para diminuir o número de JOIN na consulta.
Editor da página -> selecione o widget JetEngine Listing Grid Ative 'Lazy load' ou 'Use load more' e defina 'Posts per page' para um valor baixo (ex.: 12) Remova do filtro e da ordenacao os campos meta que não são essenciais - Adicione um indice composto em wp_postmeta para as meta_keys quentes: Para os campos mais filtrados, crie um indice composto em (meta_key, meta_value) com um prefixo de tamanho, permitindo que o MySQL use indice em vez de varrer a tabela. Faça backup antes, porque a criação de indice em wp_postmeta grande bloqueia a tabela durante a operacao.
CREATE INDEX full_meta_key_value ON wp_postmeta (meta_key(64), meta_value(64)); ANALYZE TABLE wp_postmeta; EXPLAIN SELECT ... -- confirme que a query agora usa o novo indice na coluna key - Migre dados de alto volume para Custom Content Types do JetEngine: Para catalogos e diretorios grandes, troque os campos meta por Custom Content Types do JetEngine, que gravam em uma tabela própria em vez do wp_postmeta. Consultas em tabela dedicada com colunas indexadas substituem os JOIN caros de meta_query e reduzem o tamanho da wp_postmeta.
Painel WP -> JetEngine -> Custom Content Types -> Add New Defina os campos como colunas do Content Type (gravadas em tabela própria, fora do wp_postmeta) Reaponte os Listing Grids para o Content Type e remova os campos meta antigos após validar - Ative um cache de objeto persistente: Ative Redis ou Memcached como cache de objeto persistente para evitar refazer a mesma consulta no banco a cada carregamento. A documentação de performance do WordPress aponta que, sem esse cache, o servidor le do banco em todo page view e sobrecarrega o MySQL nos picos.
Confirme com a hospedagem que ha Redis ou Memcached disponível Painel WP -> Plugins -> instale um plugin de object cache (ex.: Redis Object Cache) e clique em 'Enable Object Cache' Recarregue a página lenta e compare o tempo total no Query Monitor
<?php
/**
* Tira do filtro AJAX do JetEngine os campos meta mais pesados,
* substituindo a comparacao por meta_value (sem indice em wp_postmeta)
* por um filtro de taxonomia indexado, que usa o term_relationships.
*
* Coloque no functions.php do tema filho ou em um plugin proprio.
*/
add_action( 'pre_get_posts', 'full_jetengine_otimiza_listing' );
function full_jetengine_otimiza_listing( $query ) {
if ( is_admin() || ! $query->is_main_query() ) {
return;
}
// Aplica so na listagem do catalogo (ajuste o post_type).
if ( 'catalogo' !== $query->get( 'post_type' ) ) {
return;
}
// 1) Pagina os resultados: evita trazer milhares de linhas de uma vez.
$query->set( 'posts_per_page', 12 );
// 2) Nao calcula o total de linhas encontradas (SQL_CALC_FOUND_ROWS),
// que e caro em tabelas grandes quando a paginacao exata nao e critica.
$query->set( 'no_found_rows', true );
// 3) Troca o filtro por meta_value (LONGTEXT sem indice) por taxonomia,
// que resolve via term_relationships indexado em vez de JOIN no wp_postmeta.
$marca = isset( $_GET['marca'] ) ? sanitize_title( wp_unslash( $_GET['marca'] ) ) : '';
if ( $marca ) {
$query->set( 'meta_query', array() ); // remove a meta_query pesada
$query->set( 'tax_query', array(
array(
'taxonomy' => 'marca',
'field' => 'slug',
'terms' => $marca,
),
) );
}
}














