# Como corrigir queries lentas no banco com JetEngine e ACF PRO no WordPress

As queries lentas do JetEngine e ACF PRO no banco acontecem quando listings e filtros disparam meta_query pesadas sobre a tabela wp_postmeta sem indice útil, ou quando muitos campos são gravados como meta em vez de uma tabela dedicada, forçando JOINs e leituras caras a cada carregamento.

## 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.

**Antes de começar:** Antes de criar indices, rodar comandos no MySQL ou migrar campos para Custom Content Types, faça um backup completo do site (arquivos e banco de dados) ou teste primeiro em um ambiente de staging. Criar indice em uma wp_postmeta grande bloqueia a tabela durante a operacao e pode deixar o site indisponivel se feito direto em producao.

## 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.

Erros relacionados

- [Como corrigir as queries lentas do JetEngine no banco de dados](https://full.services/wp-fixer/corrigir-jetengine-queries-lentas/)
- [Como otimizar o wp_options para reduzir queries lentas](https://full.services/wp-fixer/otimizar-wp-options-queries-lentas/)
- [Como otimizar o banco de dados WordPress para velocidade](https://full.services/wp-fixer/otimizar-banco-dados-wordpress/)

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

1. 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
```

2. 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
```

3. 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
```

4. 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
```

5. 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
```

6. 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
```


## Código

```php
<?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,
            ),
        ) );
    }
}
```

## Perguntas frequentes

### Por que o JetEngine e o ACF PRO deixam o banco lento

Porque, na configuração padrão, ambos gravam cada campo como uma linha em wp_postmeta. Quando um Listing Grid filtra por esses campos, o WordPress monta uma meta_query com um JOIN em wp_postmeta por condicao, e a coluna meta_value não tem indice útil, entao o MySQL varre muitas linhas a cada carregamento.

### Como descobrir qual query do JetEngine esta lenta

Use o plugin Query Monitor logado como administrador e abra o painel Database Queries na página lenta, ordenando por tempo. Confirme com o slow query log do MySQL e rode EXPLAIN na consulta para ver os JOIN em wp_postmeta e validar que a meta_query e o gargalo.

### Criar indice em wp_postmeta resolve as queries lentas do JetEngine

Ajuda nos campos mais filtrados, porque um indice composto em meta_key e um prefixo de meta_value permite ao MySQL usar indice em vez de varrer a tabela. Faça backup antes, já que criar indice em uma wp_postmeta grande bloqueia a tabela durante a operacao.

### O que são Custom Content Types do JetEngine e por que ajudam na performance

São um recurso do JetEngine que armazena dados em uma tabela própria do banco, em vez de gravar tudo como meta no wp_postmeta. Consultas em tabela dedicada com colunas indexadas substituem os JOIN caros de meta_query, reduzem o tamanho do wp_postmeta e aceleram listagens de alto volume.

### Vale a pena migrar campos do ACF para Custom Content Types

Vale quando o volume e alto, como catalogos e diretorios com muitos itens e filtros. Campos pontuais por post podem continuar como meta do ACF, mas dados que alimentam listagens grandes ganham muito ao sair do wp_postmeta para uma tabela dedicada do Content Type.

### O cache de objeto resolve sozinho as queries lentas

Não sozinho, mas ajuda muito. A documentação de performance do WordPress aponta que sem um cache de objeto persistente o servidor le do banco a cada page view. Com Redis ou Memcached, consultas repetidas vem da memória, mas a meta_query pesada ainda deve ser reduzida ou movida para tabela própria.

### Por que o filtro AJAX do JetSmartFilters fica lento

Porque cada campo combinado no filtro adiciona uma condicao a meta_query, e cada condicao vira um JOIN em wp_postmeta. Quanto mais campos meta no filtro e quanto maior a tabela, mais cara a consulta. Reduzir o número de campos filtraveis e paginar os resultados alivia o banco.

### Posso apenas aumentar os recursos do servidor em vez de otimizar a query

Mais CPU e memória adiam o problema, mas não corrigem a causa: a meta_query continua varrendo wp_postmeta a cada carregamento. Conforme o site e a tabela crescem, o gargalo volta. Otimizar a consulta, indexar e mover dados de volume para tabela própria e a correção duradoura.

**Fonte:** [WordPress Developer — Optimization (Advanced Administration)](https://developer.wordpress.org/advanced-administration/performance/optimization/)
