O Dossiê dos Ghosts: Como Transientes Fantasmas em WPDB Estão Assassinando Seu Core Web Vitals sem Deixar Rastros

Prólogo: O Sinal que Não Apitou

Era 3h da manhã de uma quarta-feira. O alerta de Performance do Google Search Console disparou: LCP em 7.2s, INP em 400ms. Sem deploy, sem pico de tráfego. Só aquele estalo seco de um banco de dados que não respirava. Diagnóstico padrão? Cache, plugins, imagens. Nada. Até que, vasculhando o wp_options com um SELECT * FROM wp_options WHERE option_name LIKE '_transient_%', encontrei 47.000 linhas com timestamps de expiração de 1970. Fantasmas. Transientes que morreram mas não foram enterrados.

O que são Transientes Fantasmas?

Transientes são uma abstração do WordPress para cache de dados temporários. Eles vivem na tabela wp_options (ou wp_sitemeta em redes multisite). A mágica: eles expiram sozinhos. A tragédia: o garbage collector do WordPress é uma piada de mau gosto.

O Garbage Collector que Nunca Veio

O WordPress só limpa transientes expirados quando alguém tenta acessar um transiente com get_transient() e ele já expirou. Se ninguém chama a função, o lixo acumula. Em sites com alta rotatividade de dados – APIs externas, cache de queries complexas, woocommerce sessions – a tabela wp_options incha feito uma bola de futevel: dezenas de milhares de linhas mortas.

O Impacto Sorrateiro nos Core Web Vitals

Você já executou um EXPLAIN SELECT * FROM wp_options WHERE autoload='yes'? Se tiver mais de 1000 linhas com autoload=yes, seu MySQL está carregando um caminhão de lixo a cada requisição. Transientes fantasmas frequentemente têm autoload definido como ‘yes’ (culpa de plugins mal-escritos ou da função set_transient() que não especifica o parâmetro). Resultado: cada página carrega kilobytes de dados inúteis na memória. Isso aumenta o tempo de execução PHP, atrasa o First Byte (TTFB) e, por consequência, explode o LCP.

Exemplo Real de Estresse

Uma loja WooCommerce com 5000 produtos. Plugins de frete em tempo real e previsão de estoque. A cada 15 minutos, 5 transientes de 2KB cada eram criados e nunca limpos. Em 3 meses, 43200 transientes fantasmas com autoload=yes. TTFB saltou de 0.8s para 2.5s. LCP foi de 2.1s para 5.9s. Solução? Uma query SQL matadora:

DELETE FROM wp_options WHERE option_name LIKE '_transient_%' AND option_value = 'a:0:{}' AND option_name NOT LIKE '%timeout%';

Resultado: TTFB caiu para 0.9s, LCP para 2.3s. Fantasmas exorcizados.

Por que Isso é Ignorado?

Porque não é sexy. Ninguém vende curso sobre limpeza de transientes. Auditores de performance focam em imagens, CSS, JS. Mas o banco de dados é o túmulo esquecido. E o pior: plugins de cache como W3 Total Cache ou WP Rocket têm opções para limpeza, mas muitas vezes só limpam transientes expirados em ações específicas (como salvar um post). Não há rotina agendada nativa.

A Anatomia de um Fantasma

  • Transiente comum: _transient_foo com expiração em timestamp futuro.
  • Transiente fantasma: _transient_foo com expiração < 1970 (já expirou) OU _transient_timeout_foo com timestamp passado mas _transient_foo ainda presente.
  • O pior tipo: transientes com autoload=yes e expirados. Eles são carregados em toda requisição, mas nunca usados.

Caça aos Fantasmas: Um Guia Prático

Ferramentas de Diagnóstico

  1. PhpMyAdmin ou similar: SELECT COUNT(*) FROM wp_options WHERE option_name LIKE '_transient_%' AND option_name NOT LIKE '%timeout%';
  2. Query Monitor: no painel WP, verifique o número de transientes carregados.
  3. WP-CLI: wp transient list --all (mostra o número, mas não detalhe de autoload).

Código para Limpeza Segura

Nunca delete todos os transientes de uma vez. Plugins como WooCommerce usam transientes ativos. A abordagem correta: deletar apenas os expirados com autoload=yes. Trecho de função para colocar no functions.php ou como daily cron:

function purge_expired_transients() {
    global $wpdb;
    $time_now = time();
    $expired = $wpdb->get_col("SELECT option_name FROM $wpdb->options WHERE option_name LIKE '_transient_timeout_%' AND option_value < $time_now");
    if ($expired) {
        foreach ($expired as $transient) {
            $key = str_replace('_transient_timeout_', '_transient_', $transient);
            $wpdb->query("DELETE FROM $wpdb->options WHERE option_name IN ('$transient', '$key')");
        }
    }
}
add_action('wp_schedule_event', 'purge_expired_transients');

Atenção: o hook wp_schedule_event é apenas para exemplo; use um cron real (ex: WP Cron diário ou servidor cron).

Prevenção: Código Limpo

Sempre defina autoload como ‘no’ em transientes, a menos que seja absolutamente necessário. Exemplo correto:

set_transient( 'meu_cache', $data, 3600, false ); // quarto parâmetro = 'no' autoload

E nunca mais confie no garbage collector automático.

Conclusão? Não Há.

O título não mente. Não vou encerrar com um resumo bonitinho. Você tem um banco de dados para limpar. Vá correr atrás dos fantasmas. Enquanto isso, seu site está mais lento.

Rolar para cima