O cache de consulta é um recurso muito bom, mas não fique tentado a prestar muita atenção a ele e não fique muito grande. A compreensão de alguns de seus internos provavelmente ajudará nesse sentido.
O cache da consulta começa como um grande bloco contíguo de memória disponível. Então "blocos" são esculpidos neste grande bloco:
- cada consulta em cache recebe um bloco
- o conjunto de resultados complementar leva um bloco
- cada tabela referenciada por qualquer consulta em cache (não importa quantas consultas que referenciam essa tabela estejam no cache) também recebe um bloco, um por tabela.
O tamanho do bloco é dinâmico, mas o servidor aloca um mínimo de query_cache_min_res_unit
bytes por bloco, com um padrão típico de 4096 bytes.
Sempre que as consultas, os resultados que os acompanham e as referências de tabela são removidas do cache, tornando-se invalidadas pelas alterações nas tabelas subjacentes ou removendo espaço para consultas mais recentes, isso deixa novos buracos do tamanho do tamanho desses blocos e o número de "blocos livres" geralmente aumenta ... embora se dois ou mais blocos contíguos são liberados, o número de "blocos livres" aumenta apenas 1 e os "blocos livres" não aumentarão se os novos- blocos liberados são contíguos a um bloco já livre - o tamanho desse bloco livre se torna maior. Qualquer bloco aberto de memória livre no cache de consulta é contado como 1 bloco livre.
Obviamente, um bloco livre menor do que query_cache_min_res_unit
não será usado.
Portanto, o cache da consulta fragmenta. Se o servidor quiser armazenar em cache uma nova consulta e nenhum bloco livre de tamanho suficiente puder ser organizado (essa descrição é enganosamente simples, porque o algoritmo subjacente é complicado), outra coisa precisa ser removida ... essa é a sua Qcache_lowmem_prunes
. Existe um algoritmo "menos usado recentemente" (LRU) que decide o que será removido.
Seria sensato perguntar por que o servidor não desfragmenta a memória ... mas isso não faria sentido. O cache da consulta ajuda quando pode, mas não é nada estratégico. Você não deseja investir o tempo de processamento (especialmente o tempo gasto em um bloqueio global) em tarefas desnecessárias de manutenção.
Seria contraproducente para o servidor gastar tempo reorganizando - desfragmentando - a memória no cache de consultas, pois os resultados armazenados em cache estão mudando constantemente e o objetivo principal do cache é melhorar o desempenho.
O bloqueio global é uma boa razão para você não usar um cache de consultas excessivamente grande ... o servidor passará muito tempo lá, pois as consultas aguardam a sua vez para ver se elas estão em cache e seu desempenho será prejudicado. .
Mas isso qcache_free_blocks
é essencialmente um indicador de fragmentação do espaço livre. Agora, existem muitos blocos não contíguos de memória disponível no cache da consulta. Para que uma nova consulta seja inserida no cache, deve haver um pedaço grande de espaço livre suficiente para conter a consulta, seus resultados e (às vezes) suas referências de tabela. Se não houver, algo mais tem que acontecer ... o que você está vendo. Observe, novamente, que o espaço disponível nem sempre precisa necessariamente ser contíguo (pelo que posso ler lendo o código-fonte), mas nem todos os buracos serão preenchidos quando houver fragmentação.
Mas a fragmentação tende a se estabilizar com o tempo, para uma determinada carga de trabalho, já que normalmente nada fica no cache de consultas pelo tempo que você poderia esperar.
Isso ocorre porque, de certa forma, o cache da consulta é brilhante em sua simplicidade.
Sempre que os dados em uma tabela referenciada por uma consulta em cache são alterados, todas as consultas que envolvem essa tabela são removidas do cache - mesmo se a alteração não afetar os resultados em cache. Isso é verdade mesmo se uma tabela for alterada, mas não for alterada, como no caso de uma transação do InnoDB que é revertida. As entradas do cache de consulta que referenciam essa tabela já foram eliminadas.
Além disso, o cache da consulta é verificado para cada consulta recebida antes que o servidor realmente analise a consulta. A única coisa que corresponderá é outra consulta exatamente igual, byte por byte. SELECT * FROM my_table
e select * from my_table
não são idênticos byte a byte, portanto, o cache da consulta não percebe que é a mesma consulta.
FLUSH QUERY CACHE
não esvazia o cache da consulta. Ele desfragmenta o cache da consulta, e é por isso que se Qcache_free_blocks
torna "1". Todo o espaço livre é consolidado.
RESET QUERY CACHE
na verdade libera (limpa todo o conteúdo) o cache da consulta.
FLUSH STATUS
limpa os contadores, mas isso não é algo que você deseja fazer rotineiramente porque zera a maioria das variáveis de status SHOW STATUS
.
Aqui estão algumas demonstrações rápidas.
Linha de base:
mysql> show status like '%qcache%';
+-------------------------+----------+
| Variable_name | Value |
+-------------------------+----------+
| Qcache_free_blocks | 1 |
| Qcache_free_memory | 67091120 |
| Qcache_hits | 0 |
| Qcache_inserts | 0 |
| Qcache_lowmem_prunes | 0 |
| Qcache_not_cached | 1 |
| Qcache_queries_in_cache | 0 |
| Qcache_total_blocks | 1 |
+-------------------------+----------+
Execute uma consulta ...
mysql> select * from junk where id = 2;
O total de blocos aumentou em 3, as inserções em 1 e as consultas no cache são 1.
+-------------------------+----------+
| Variable_name | Value |
+-------------------------+----------+
| Qcache_free_blocks | 1 |
| Qcache_free_memory | 67089584 |
| Qcache_inserts | 1 |
| Qcache_queries_in_cache | 1 |
| Qcache_total_blocks | 4 |
+-------------------------+----------+
Execute a mesma consulta, mas com letras maiúsculas diferentes ...
mysql> SELECT * FROM junk where id = 2;
Esta consulta foi armazenada em cache separadamente. O total de blocos aumentou apenas 2 porque já tínhamos um bloco alocado para a tabela.
+-------------------------+----------+
| Variable_name | Value |
+-------------------------+----------+
| Qcache_free_blocks | 1 |
| Qcache_free_memory | 67088560 |
| Qcache_inserts | 2 |
| Qcache_queries_in_cache | 2 |
| Qcache_total_blocks | 6 |
+-------------------------+----------+
Agora, alteramos uma linha diferente na tabela.
mysql> update junk set things = 'items' where id = 1;
As consultas e a referência da tabela são invalidadas do cache, deixando-nos 1 bloco livre contíguo, toda a memória cache liberada e todo o espaço livre consolidado em um bloco.
+-------------------------+----------+
| Variable_name | Value |
+-------------------------+----------+
| Qcache_free_blocks | 1 |
| Qcache_free_memory | 67091120 |
| Qcache_queries_in_cache | 0 |
| Qcache_total_blocks | 1 |
+-------------------------+----------+
O MySQL não armazenará uma consulta no cache que não seja determinística - como SELECT NOW();
qualquer consulta que você diga especificamente para não armazenar em cache. SELECT SQL_NO_CACHE ...
é a diretiva para informar ao servidor para não armazenar os resultados no cache. É útil para comparar o verdadeiro tempo de execução de uma consulta quando o cache está fornecendo uma resposta enganosamente rápida nas execuções subseqüentes.