Por que o banco de dados é frequentemente ignorado
Quando uma loja WooCommerce fica lenta, o instinto imediato é culpar o servidor. A primeira resposta de quase todo provedor de hospedagem é oferecer um upgrade de plano. Em muitos casos, isso resolve superficialmente — mas não elimina o problema real.
O que raramente é examinado é o banco de dados. E o banco de dados do WordPress/WooCommerce tem características estruturais que acumulam problemas ao longo do tempo: a arquitetura EAV do postmeta, a tabela wp_options que cresce sem controle, e queries que simplesmente nunca foram projetadas para escala.
Trocar de servidor sem resolver o problema de banco é como contratar um caminhão maior para entregar encomendas que estão sendo embaladas errado. O caminhão vai mais rápido, mas o problema de embalagem volta a aparecer.
Este artigo mostra como identificar os gargalos reais no banco antes de tomar qualquer decisão de infraestrutura.
wp_options inflada — o problema invisível
A tabela wp_options armazena configurações do WordPress, dados de plugins, transients, cache interno e metadados variados. O problema está na coluna autoload: toda linha marcada como autoload = yes é carregada em memória a cada request PHP, mesmo que o plugin que a criou não seja necessário naquela página.
Em lojas com 30, 40, 50 plugins ativos — e principalmente em lojas que já desinstalaram plugins sem limpeza adequada — a tabela wp_options pode ter centenas de milhares de registros com autoload ativado, somando megabytes de dados carregados desnecessariamente a cada pageview.
Para diagnosticar, execute diretamente no banco:
-- Total de dados com autoload ativo
SELECT SUM(LENGTH(option_value)) / 1024 / 1024 AS total_mb
FROM wp_options
WHERE autoload = 'yes';
-- Top 20 maiores entradas com autoload
SELECT option_name, LENGTH(option_value) / 1024 AS size_kb, autoload
FROM wp_options
WHERE autoload = 'yes'
ORDER BY LENGTH(option_value) DESC
LIMIT 20;
-- Contagem total de registros com autoload
SELECT COUNT(*) FROM wp_options WHERE autoload = 'yes';
Se o total de dados com autoload ultrapassar 1MB, você tem um problema. Valores acima de 5MB são críticos e explicam boa parte da lentidão genérica da loja.
Outra categoria de problema nessa tabela são os transients — dados temporários de cache que plugins escrevem e que deveriam ter prazo de validade. Muitos plugins criam transients e nunca os limpam adequadamente:
-- Contar transients expirados ainda na tabela
SELECT COUNT(*) FROM wp_options
WHERE option_name LIKE '_transient_%'
AND option_name NOT LIKE '_transient_timeout_%';
A limpeza de transients expirados deve ser parte da rotina de manutenção. Via WP-CLI: wp transient delete --expired.
Como ativar e ler o slow query log no MySQL
O slow query log é a ferramenta mais direta para identificar queries problemáticas em produção. Ele registra todas as queries que excedem um tempo limite configurável, com detalhes de tempo de execução, número de linhas examinadas e o SQL completo.
Para ativar, adicione ao arquivo /etc/mysql/my.cnf (ou my.ini no Windows) na seção [mysqld]:
[mysqld]
slow_query_log = 1
slow_query_log_file = /var/log/mysql/slow.log
long_query_time = 1
log_queries_not_using_indexes = 1
min_examined_row_limit = 100
O parâmetro log_queries_not_using_indexes é especialmente útil — ele captura queries sem índice mesmo que sejam rápidas agora, porque essas queries ficam cada vez mais lentas conforme a tabela cresce.
Após algumas horas (ou dias, se o tráfego for baixo), analise o log com mysqldumpslow:
# Top 10 queries por tempo acumulado total
mysqldumpslow -s t -t 10 /var/log/mysql/slow.log
# Top 10 queries por pior tempo individual
mysqldumpslow -s at -t 10 /var/log/mysql/slow.log
# Filtrar apenas queries do WordPress (contêm wp_)
mysqldumpslow -s t /var/log/mysql/slow.log | grep wp_
As queries mais problemáticas em WooCommerce quase sempre envolvem: buscas em wp_postmeta sem índice em meta_value, JOINs entre wp_posts e wp_postmeta com múltiplos filtros, e SELECTs em wp_woocommerce_order_items com volume alto.
Alternativa sem acesso ao servidor: Se você não tem acesso ao arquivo de configuração do MySQL, ative o slow log temporariamente via SQL com privilégios de SUPER: SET GLOBAL slow_query_log = 'ON'; SET GLOBAL long_query_time = 1;. Isso persiste até o próximo restart do MySQL.
Query Monitor — diagnóstico direto no WordPress
O plugin Query Monitor (gratuito, disponível no repositório oficial do WordPress) é a ferramenta mais prática para diagnosticar queries em tempo real sem precisar de acesso ao servidor.
Após instalar e ativar, um painel aparece na barra de admin com informações detalhadas sobre cada pageview:
- Queries lentas: lista queries que excederam 0.05s (configurável)
- Queries duplicadas: a mesma query sendo executada múltiplas vezes — sinal claro de problema N+1
- Caller: qual plugin ou função PHP disparou cada query — essencial para rastrear a origem
- Total de queries por página: páginas com mais de 50–100 queries merecem atenção
O que procurar especificamente no Query Monitor para WooCommerce:
- Queries em
wp_postmetacomWHERE meta_key = '...'sem índice composto em(post_id, meta_key) - Queries na listagem de pedidos (
/wp-admin/edit.php?post_type=shop_order) com tempo elevado - Queries duplicadas disparadas por plugins de analytics, review ou chat
- Queries com
SELECT *em tabelas grandes — desperdiçam memória e I/O
Remova o Query Monitor em produção após o diagnóstico. Ele adiciona overhead mensurável por coletar e formatar dados de todas as queries. Use em ambiente de staging ou em horários de baixo tráfego em produção.
postmeta e orderitemmeta — queries N+1 que travam a listagem
O modelo de dados do WordPress para pedidos WooCommerce é estruturalmente problemático em escala. Cada pedido é um post (wp_posts), e cada metadado do pedido (status, cliente, endereço, forma de pagamento, etc.) é uma linha separada em wp_postmeta.
Para exibir uma listagem de 20 pedidos no admin, o WooCommerce precisa:
- 1 query para buscar os 20 posts de pedido
- N queries para buscar os metadados de cada pedido (N+1 clássico)
- Queries adicionais para order items em
wp_woocommerce_order_items - Queries para order item meta em
wp_woocommerce_order_itemmeta
Em lojas com milhares de pedidos, a listagem pode disparar 200–500 queries por pageview — completamente normal pela arquitetura, mas impraticável sem otimização.
A solução de longo prazo é migrar para o HPOS (High-Performance Order Storage), o novo sistema de armazenamento de pedidos do WooCommerce que usa tabelas dedicadas (wc_orders, wc_orders_meta) em vez do modelo postmeta. HPOS reduz drasticamente o número de queries e permite índices adequados:
# Verificar se HPOS está disponível e ativar via WP-CLI
wp option get woocommerce_feature_custom_order_tables_enabled
wp option update woocommerce_feature_custom_order_tables_enabled yes
Antes de migrar para HPOS em produção, verifique a compatibilidade de todos os plugins críticos no painel WooCommerce → Status → Ferramentas.
Índices ausentes — como identificar e criar sem derrubar produção
O MySQL pode sugerir índices ausentes através do EXPLAIN. Para qualquer query lenta identificada no slow log, execute:
EXPLAIN SELECT p.ID, p.post_status, pm.meta_value
FROM wp_posts p
JOIN wp_postmeta pm ON pm.post_id = p.ID
WHERE p.post_type = 'shop_order'
AND pm.meta_key = '_customer_user'
AND pm.meta_value = '42';
Se o campo type mostrar ALL (full table scan) ou rows mostrar um número muito alto relativo ao resultado, é sinal de índice ausente. O campo Extra com Using filesort ou Using temporary indica ineficiência.
Para criar índices sem derrubar produção em MySQL 5.6+, use ALTER TABLE ... ALGORITHM=INPLACE, LOCK=NONE:
-- Índice composto para buscas por meta_key + meta_value no postmeta
ALTER TABLE wp_postmeta
ADD INDEX idx_meta_key_value (meta_key(20), meta_value(20))
ALGORITHM=INPLACE, LOCK=NONE;
-- Índice para busca por tipo de post + status
ALTER TABLE wp_posts
ADD INDEX idx_post_type_status (post_type, post_status)
ALGORITHM=INPLACE, LOCK=NONE;
ALGORITHM=INPLACE, LOCK=NONE permite que a tabela continue disponível para leitura e escrita durante a criação do índice. Em tabelas grandes (milhões de registros), a operação pode levar minutos — monitore o progresso com SHOW PROCESSLIST.
Limpeza e manutenção preventiva
O banco de dados do WooCommerce precisa de manutenção periódica. As operações abaixo devem ser rotina — mensalmente em lojas pequenas, semanalmente em lojas com alto volume:
# Via WP-CLI — limpeza de revisões de posts
wp post delete $(wp post list --post_type='revision' --format=ids) --force
# Limpar transients expirados
wp transient delete --expired
# Otimizar tabelas (equivalente ao OPTIMIZE TABLE do MySQL)
wp db optimize
# Limpar carrinhos abandonados com mais de 7 dias
wp wc tool run clear_abandoned_carts --user=1
# Ver tamanho atual de cada tabela
wp db query "SELECT table_name, ROUND(((data_length + index_length) / 1024 / 1024), 2) AS size_mb FROM information_schema.TABLES WHERE table_schema = DATABASE() ORDER BY (data_length + index_length) DESC LIMIT 15;"
Para lojas que processam muitos pedidos, considere também arquivar pedidos antigos em uma tabela separada ou migrar para HPOS — a combinação das duas estratégias é o que diferencia lojas WooCommerce que escalam das que emperram no mesmo problema todo trimestre.
WooCommerce lento e você não sabe onde está o gargalo?
Faço diagnóstico completo de banco de dados WooCommerce: análise de slow queries, tamanho de wp_options, índices ausentes e viabilidade de migração para HPOS. Entrego um relatório priorizado com o que resolver primeiro.