optimização

MySQL & NoSQL – Memcached Plugin

Muita gente já deve ter ouvido falar nos bancos de dados NoSQL e uma das ferramentas NoSQL muito utilizada é o memcached, no qual adicionamos uma camada de cache entre a aplicação e o banco de dados. Desde a versão 5.6 do MySQL, foi disponibilizado um plugin de integração entre o MySQL e o Memcached. Neste artigo publicado no iMasters eu mostro como instalar e configurar esta integração.

Esquentando o InnoDB Buffer Pool

Uma das mais importantes configurações para quem usa InnoDB é o innodb_buffer_pool_size, ele basicamente armazena dados e índices em memória, quando o MySQL recebe uma query e as paginas que contem o resultado da pesquisa/índice estao armazenadas no buffer, o MySQL não precisar ler essas informações do disco, o que é muito mais rápido (velocidade da memória vs velocidade do disco) .

Como estas informações estão armazenadas na memória, cada vez que o MySQL é re-iniciado, o buffer é apagado, e para “esquentar” o buffer normalmente leva-se algum tempo.

Para agilizar este processo, vamos utilizar 2 variáveis para salvar e restaurar as referencias das paginas que estão armazenadas no buffer, esta é uma nova funcionalidade adicionada no MySQL 5.6 (essa opção já pode ser encontrada em algumas versões anteriores do Percona Server e MariaDB )

Se o seu servidor já está rodando e com o buffer “quente”, vamos setar a variável innodb_buffer_pool_dump_at_shutdown para fazer efeito no próximo shutdown ou restart.

SET GLOBAL innodb_buffer_pool_dump_at_shutdown = 1;

Agora, no próximo shutdown ou restart, um arquivo chamado ib_buffer_pool será criado no datadir do MySQL (você pode alterar este nome configurando a variável innodb_buffer_pool_filename ).

Próximo passo é configurar o MySQL para que ele leia o conteúdo deste arquivo e carregue os dados de volta para o InnoDB buffer, para isso, vamos adicionar a variável innodb_buffer_pool_load_at_startup ao my.cnf (e também a variável innodb_buffer_pool_dump_at_shutdown, para que o MySQL salve o buffer pool a cada shutdown/restart):

[mysqld]
innodb_buffer_pool_dump_at_shutdown = 1
innodb_buffer_pool_load_at_startup = 1

Agora podemos reiniciar o MySQL, como mencionado anteriormente, um arquivo será criado no datadir do MySQL, o conteúdo é similar ao seguinte:

[root@marcelodb data]# tail ib_buffer_pool
0,69618
0,69619
0,69620
0,69621
0,69622
0,69623
0,69624
0,69625
0,69626
0,69627

Quando reiniciamos o MySQL, veremos 2 mensagens no log:

2014-01-07 19:53:54 7fad34bc7700 InnoDB: Dumping buffer pool(s) to .//ib_buffer_pool
2014-01-07 19:53:54 7fad34bc7700 InnoDB: Buffer pool(s) dump completed at 140107 19:53:54

Isto significa que o MySQL escreveu o arquivo contendo as referencias as paginas que estavam armazenadas no InnoDB buffer poll.

2014-01-07 19:54:01 7f68eee67700 InnoDB: Buffer pool(s) load completed at 140107 19:54:01

Esta mensagem, significa que o MySQL terminou de restaurar o conteúdo do InnoDB buffer pool de volta.

Este progresso pode ser controlado através das variáveis Innodb_buffer_pool_dump_status e Innodb_buffer_pool_load_status:

mysql> SHOW STATUS LIKE 'Innodb_buffer_pool_load_status';
+--------------------------------+------------------------+
| Variable_name                  | Value                  |
+--------------------------------+------------------------+
| Innodb_buffer_pool_load_status | Loaded 5121/6441 pages |
+--------------------------------+------------------------+
1 row in set (0.00 sec)

mysql> SHOW STATUS LIKE 'Innodb_buffer_pool_load_status';
+--------------------------------+--------------------------------------------------+
| Variable_name                  | Value                                            |
+--------------------------------+--------------------------------------------------+
| Innodb_buffer_pool_load_status | Buffer pool(s) load completed at 140108 16:55:05 |
+--------------------------------+--------------------------------------------------+
1 row in set (0.00 sec)

Case deseja, pode se salvar/restaurar o conteúdo do InnoDB buffer pool através da variáveis innodb_buffer_pool_dump_now e innodb_buffer_pool_load_now.

Caso utilize InnoDB como storage engine em alguma tabela, este processo pode trazer grandes benefícios e minimizar os impactos de um restart.

Optimizar consultas em MySQL com query cache

 

EDIT: Cuidado. Query Cache pode causar problemas de performance e escalabilidade em ambientes com muitas sessões simultâneas. Use com cuidado.

Hoje vamos falar de uma ferramenta bem bacana do MySQL, o query cache.
o query cache salva resultados de SELECT’s já executados e que seus dados brutos não tenham sido alterados tornando assim o tempo de resposta da query muito mais otimizada, pois ele vai buscar da memória e não do disco.
Ele pode trabalhar de 3 maneiras diferentes, no nosso my.ini dentro do grupo [mysqld]:
query_cache_type = 0
Desligado
query_cache_type = 1
Ligado para todas as query’s
query_cache_type = 2
Ligado sobre demanda

Mas qual a melhor maneira de utilizar o query cache?
Tendo em vista que toda a vez que você altera dados em alguma tabela, ele invalida o cache da mesma, o mais indicado é você fazer um mapeamento da frequencia de atualização das tabelas e utilizar o cache para as que não tenham uma frequencia grande a atualização / inserção, para que assim, o cache lhe dê um ganho de performance, e não fique sobrecarregando o servidor tendo que invalidar muitas querys.
Por exemplo, a tabela de registros de log do sistema, a cada ação do usuário ele irá inserir um novo dado nesta tabela, logo ela não é uma boa candidata a ser cacheada, já a tabela de noticias do site, recebe atualizações 2 vezes ao dia, tá aí, uma boa candidata a ser cacheada,

Vou mostrar na prática que resultados conseguimos alcançar com o query cache:

estou com ele setado para ON DEMAND – query_cache_type = 2
Possuo uma tabela com 100 milhões de registros, para a opção ON DEMAND temos que especificar no select que queremos que ele utilize o cache com SQL_CACHE:

    Rodando a consulta pela primeira vez:

mysql> SELECT SQL_CACHE * FROM noticia WHERE conteudo LIKE "%8555556%";
. . .
20 rows in set (2 min 15.20 sec)

Neste momento, esquentamos o cache com a nossa consulta, ele demorou o tempo padrão, porém colocou-a em cache, veja o resultado da mesma query:
mysql> SELECT SQL_CACHE * FROM noticia WHERE conteudo LIKE "%8555556%";
...
20 rows in set (0.00 sec)

A mesma consulta demorou 0 segundos para trazer os resultados, pois estava guardada em cache.
Mas qual o tamanho do cache de consulta?
Como tudo no MySQL, ele é configurável através da opção query_cache_size, valores em torno de 16M são recomendados, dependendo da capacidade do seu servidor.

Caso você faça a analise e veja que a maioria das suas tabelas devem ser cacheadas, vocÊ pode usar o processo inverso, ou seja, setar a variavel query_cache_type = 1 isso fará com que todas as consultas sejam cacheadas e expecificar nos selects que não devem cachear com SELECT SQL_NO_CACHE * FROM ...
Utilizar qualquer uma das funções abaixo inutiliza o cache na consulta:
BENCHMARK() CONNECTION_ID() CONVERT_TZ()
CURDATE() CURRENT_DATE() CURRENT_TIME()
CURRENT_TIMESTAMP() CURTIME() DATABASE()
ENCRYPT() with one parameter FOUND_ROWS() GET_LOCK()
LAST_INSERT_ID() LOAD_FILE() MASTER_POS_WAIT()
NOW() RAND() RELEASE_LOCK()
SLEEP() SYSDATE() UNIX_TIMESTAMP(
USER() UUID() UUID_SHORT()

Lembrando que para a utilização do query cache, select * from ... é diferente de SELECT * FROM ...