Dicas de Performance para Sites com Muito Tráfego

Pensemos num web site com 14.000 artigos e perto de 400.000 comentários.
Será que o WordPress é um bom script para fazer um site grande como este?
Se sim, será que tem capacidade para crescer e manter performance?
Nós pensamos que sim, e por isso deixamos as nossas dicas para optimizar o WordPress para sites com bastante tráfego e muito conteúdo:

Post Revisions (Revisões de Artigos)
Este é um dos pontos fracos do WordPress.
Em sites como o que indicamos pode chegar a haver mais de 30.000 revisões para os 14.000 artigos.
Isto faz com que a tabela na base de dados seja enorme e crie um ponto de grande lentidão para o site, pois o WordPress tem de pesquisar demasiados registos sem necessidade.

Dica
Primeiro comecemos por favor um backup da table wp_posts, e de seguida vamos usar um comando simples de MySQL para remover o excesso de revisões antigas dos posts, o que fará reduzir drásticamente a tabela.
O comando:

[sql]DELETE FROM `wp_posts` WHERE post_type = ‘revision’ AND post_date NOT LIKE ‘2012-%'[/sql]

Número Grande de Comentários
Este é um dos pontos que temos de ter muita atenção, especialmente com a tabela wp_comments, que no nosso exemplo tem 400.000 registos.
Mesmo em sites pequenos e com poucos comentários, consegue-se perceber que existe problemas com o WordPress em várias queries de MySQL, especialmente de comentários.
Ora, a partir da versão 3.2 do WordPress, na barra de Administração, aparece o número de comentários tanto para Administradores como para Editores.
Contar o número de comentários é dispendioso para uma base de dados MySQL e é um ponto de fraca performance quando falamos de um WordPress já com muitos artigos e comentários, como o do nosso exemplo.
A query responsavél por esta contagem é:

[sql]SELECT comment_approved, COUNT(*) AS num_comments FROM wp_comments GROUP BY comment_approved;[/sql]

No nosso exemplo esta query demora 0.3 segundos, enquanto a maioria de outras queries demora entre 0.05 a 0.001 segundos.
Sem dúvida alguma, é excessivo e quando o site está a carregar, isto é uma fonte de problemas de performance e lentidão.

Para resolver este problmea, criámos um conjunto de 5 queries que fazem diminuir em muito este problema e ganhar alta performance no site:

[sql]
SELECT COUNT(comment_ID) FROM wp_comments WHERE comment_approved = ‘0’
SELECT COUNT(comment_ID) FROM wp_comments WHERE comment_approved = ‘trash’
SELECT COUNT(comment_ID) FROM wp_comments WHERE comment_approved = ‘spam’
SELECT COUNT(comment_ID) FROM wp_comments WHERE comment_approved = ‘post-trash’
SELECT COUNT(comment_ID) FROM wp_comments
[/sql]

O resultado é extraordinário, e dá um fantástico total de 0.042, uma grande diferença do actual 0.3 da query que o WordPress possui.
Para quem quiser implementar esta solução no wordpress, fica aqui o código para ser para substituir o conteúdo do /wp-includes/comment.php:

[php]
<?php
/*
This is faster than using standard query
*/
function custom_tweak_wp_count_comments( $post_id = 0 ) {
global $wpdb;

$args = func_get_args();
$post_id = $args[1];

$post_id = (int) $post_id;

$count = wp_cache_get("comments-{$post_id}", ‘counts’);

if ( false !== $count )
return $count;

$where = ‘WHERE';
if ( $post_id > 0 )
$where .= $wpdb->prepare( " comment_post_ID = %d AND", $post_id );

$unapproved = $wpdb->get_var( "SELECT COUNT( comment_ID ) FROM {$wpdb->comments} {$where} comment_approved = ‘0’ " );
$spam = $wpdb->get_var( "SELECT COUNT( comment_ID ) FROM {$wpdb->comments} {$where} comment_approved = ‘spam’ " );
$trash = $wpdb->get_var( "SELECT COUNT( comment_ID ) FROM {$wpdb->comments} {$where} comment_approved = ‘trash’ " );
$post_trash = $wpdb->get_var( "SELECT COUNT( comment_ID ) FROM {$wpdb->comments} {$where} comment_approved = ‘post-trash’ " );

/*if ( $post_id > 0 ) {
$approved = $wpdb->get_var( "SELECT COUNT( comment_ID ) FROM {$wpdb->comments} {$where} comment_approved = ‘1’ " );
}*/
$approved = $wpdb->get_var( "SELECT COUNT( comment_ID ) FROM {$wpdb->comments} " );
$approved = $approved – $unapproved – $spam – $trash – $post_trash;

$count = array();
$count[] = array( ‘comment_approved’ => ‘0’, ‘num_comments’ => $unapproved );
$count[] = array( ‘comment_approved’ => ‘1’, ‘num_comments’ => $approved );
$count[] = array( ‘comment_approved’ => ‘spam’, ‘num_comments’ => $spam );
$count[] = array( ‘comment_approved’ => ‘trash’, ‘num_comments’ => $trash );
$count[] = array( ‘comment_approved’ => ‘post-trash’, ‘num_comments’ => $post_trash );

/*
Here is the standard query for reference
*/
//$count = $wpdb->get_results( "SELECT comment_approved, COUNT( * ) AS num_comments FROM {$wpdb->comments} {$where} GROUP BY comment_approved", ARRAY_A );

$total = 0;
$approved = array(‘0′ => ‘moderated’, ‘1’ => ‘approved’, ‘spam’ => ‘spam’, ‘trash’ => ‘trash’, ‘post-trashed’ => ‘post-trashed’);
foreach ( (array) $count as $row ) {
// Don’t count post-trashed toward totals
if ( ‘post-trashed’ != $row[‘comment_approved’] && ‘trash’ != $row[‘comment_approved’] )
$total += $row[‘num_comments’];
if ( isset( $approved[$row[‘comment_approved’]] ) )
$stats[$approved[$row[‘comment_approved’]]] = $row[‘num_comments’];
}

$stats[‘total_comments’] = $total;
foreach ( $approved as $key ) {
if ( empty($stats[$key]) )
$stats[$key] = 0;
}

$stats = (object) $stats;
wp_cache_set("comments-{$post_id}", $stats, ‘counts’);

return $stats;
}
add_filter(‘wp_count_comments’, ‘custom_tweak_wp_count_comments’, 10, 2 );
?>
[/php]

Encontrar e Corrigir Queries Lentas de MySQL
Outro problema de um WordPress com muito conteúdo e tráfego é as queries lentas de MySQL. Para as descobrirmos, se formos os administradores do servidor, devemos encontrar o ficheio dentro do directório do MySQL, normalmente o /var/lib/mysql . Se não formos o administrador do servidor, então devemos falar com quem administra o nosso servidor e solicitar-lhe o log de Queries Lentas de MySQL.

Um exemplo de uma query lenta do nosso Site exemplo:

[sql]
SELECT count(*) FROM wp_comments AS c JOIN wp_posts AS p ON c.comment_post_ID = p.ID WHERE c.user_id = ‘1079’ AND c.comment_approved = ‘1’ AND p.post_status = ‘publish’ AND comment_content REGEXP ‘[[::]]’ = 1;[/sql]

Para a anlisarmos devemos usar um programa de interface com o MySQL, que normalmente em quase todos os serviços de Hosting, é o PHPMyAdmin.
No PHPMyAdmin, devemos então tentar perceber a query e se podemos melhorá-la com indexes, e o primeiro passo a fazer é correr a query colocando no inicio a palavra EXPLAIN. Este EXPLAIN vai permitir que o MySQL nos explique porque a query é lenta e onde pode levar mais indexes. Exemplo da query anterior com EXPLAIN:

[sql]
EXPLAIN SELECT count(*) FROM wp_comments AS c JOIN wp_posts AS p ON c.comment_post_ID = p.ID WHERE c.user_id = ‘1079’ AND c.comment_approved = ‘1’ AND p.post_status = ‘publish’ AND comment_content REGEXP ‘[[::]]’ = 1
EXPLAIN SELECT count(*) FROM wp_comments AS c JOIN wp_posts AS p ON c.comment_post_ID = p.ID WHERE c.user_id = ‘1079’ AND c.comment_approved = ‘1’ AND p.post_status = ‘publish’ AND comment_content REGEXP ‘[:asdf:]’ = 1;
[/sql]
+————-+——-+——–+————————————————————+——————+———+————————+——–+————-+
| select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+————-+——-+——–+————————————————————+——————+———+————————+——–+————-+
| SIMPLE | c | ref | comment_approved,comment_post_ID,comment_approved_date_gmt | comment_approved | 62 | const | 377606 | Using where |
| SIMPLE | p | eq_ref | PRIMARY | PRIMARY | 8 | site.c.comment_post_ID | 1 | Using where |
+————-+——-+——–+————————————————————+——————+———+————————+——–+————-+
2 rows in set (0.00 sec)

Esta query de MySQL está a usar o campo user_id na cláusula WHERE. E como seria de esperar
não existe um index que contenha esta campo (veja atrás o possible_key).
Então como resultado de melhoramento, o que temos de fazer é criar um novo index para este campo, que vai fazer com que a pesquisa da query vai diminuir tanto em número de registos como em tempod e reposta, melhorando e muito o desempenho do WordPress.

Todos estes truques, ajudam e muito no melhoramento do wordpress, mas uma última Dica, ou melhor, chamemos-lhe alerta, tem de ser dado, todas estas alterações que forem feitas nas tabelas podem desaparecer com um update do WordPress, por isso é necessário que documentem sempre todas as alterações para se for preciso poderem faze-las novamente.

Deixe seu comentário

*