# rm-rf.es | Administración de sistemas

Bitácora personal de un SysAdmin Gnu/Linux, Windows, BSD...

5 formas de encontrar y optimizar consultas MySQL problemáticas


MySQLA la hora de detectar problemas en servidores MySQL (cuellos de botella, uso excesivo de CPU, bajo rendimiento, lentitud, etc) es conveniente conocer las distintas opciones que nos ofrece MySQL para dar con el problema. Vamos a ver algunas de ellas:

Activar el Slow Query Log

Activar el log de consultas lentas en MySQL supondrá que en el momento que una consulta SQL supere el tiempo de ejecución establecido con la variable long_query_time quedará registrada en el log establecido. Para activarlo añadimos las siguientes directivas en el fichero de configuración my.cnf:

log-slow-queries=/var/log/mysql-slow-queries.log
long_query_time = 5

Este tema ya lo traté en un artículo anterior, para profundizar en ello acceded a la entrada a través del siguiente enlace: Slow Queries en MySQL.

Usar SHOW PROCESSLIST

Tanto desde la propia shell desde MySQL como usando mysqladmin podemos visualizar a tiempo real las consultas SQL que se están ejecutando en el servidor:

mysql> show processlist;
+----+------+-----------+------+---------+------+-------+------------------+
| Id | User | Host      | db   | Command | Time | State | Info             |
+----+------+-----------+------+---------+------+-------+------------------+
| 35 | root | localhost | NULL | Query   |    0 | NULL  | show processlist |
+----+------+-----------+------+---------+------+-------+------------------+
1 row in set (0.00 sec)

Como podéis observar, nos muestra el estado de la consulta (State), la base de datos, el comando que está ejecutando, el usuario, el host y el tiempo de ejecución, siendo este último de los puntos más importantes. Recordad que podéis formatear la salida con \G:

mysql> show processlist \G
*************************** 1. row ***************************
     Id: 35
   User: root
   Host: localhost
     db: NULL
Command: Query
   Time: 0
  State: NULL
   Info: show processlist
1 row in set (0.00 sec)

Y con mysqladmin desde la shell bash:

$ mysqladmin processlist -u root --pXXXX
+----+------+-----------+----+---------+------+-------+------------------+
| Id | User | Host      | db | Command | Time | State | Info             |
+----+------+-----------+----+---------+------+-------+------------------+
| 42 | root | localhost |    | Query   | 0    |       | show processlist |
+----+------+-----------+----+---------+------+-------+------------------+

Si queréis ver el contenido completo de la consulta SQL que se está ejecutando probablemente necesitéis utilizar SHOW FULL PROCESSLIST; en lugar de SHOW PROCESSLIST:

mysql> SHOW FULL PROCESSLIST;
+----+------+-----------+------+---------+------+-------+-----------------------+
| Id | User | Host      | db   | Command | Time | State | Info                  |
+----+------+-----------+------+---------+------+-------+-----------------------+
| 35 | root | localhost | NULL | Query   |    0 | NULL  | SHOW FULL PROCESSLIST |
+----+------+-----------+------+---------+------+-------+-----------------------+
1 row in set (0.00 sec)

Optimizar las consultas SQL con EXPLAIN

Gracias a EXPLAIN podemos obtener toda la información sobre el modo en el que una consulta SQL se ejecutaría en el servidor. Es extremadamente útil para conocer la configuración de índices en las tablas, los índices que podrían ser configurados para mejorar su rendimiento, el número de filas que se revisan, el tipo de query, etc.

Aquí tenéis un ejemplo de EXPLAIN contra la tabla City de la base de datos de muestra de MySQL (world). Para profundizar en el funcionamiento de EXPLAIN os recomiendo revisar la documentación oficial de MySQL.

mysql> EXPLAIN select * from City;
+----+-------------+-------+------+---------------+------+---------+------+------+-------+
| id | select_type | table | type | possible_keys | key  | key_len | ref  | rows | Extra |
+----+-------------+-------+------+---------------+------+---------+------+------+-------+
|  1 | SIMPLE      | City  | ALL  | NULL          | NULL | NULL    | NULL | 4079 |       |
+----+-------------+-------+------+---------------+------+---------+------+------+-------+
1 row in set (0.00 sec)
mysql> EXPLAIN select * from City \G
*************************** 1. row ***************************
           id: 1
  select_type: SIMPLE
        table: City
         type: ALL
possible_keys: NULL
          key: NULL
      key_len: NULL
          ref: NULL
         rows: 4079
        Extra:
1 row in set (0.00 sec)

Activar el log general

Una medida quizás un poco agresiva y que no debería ser ejecutada en servidores de producción. Este log (General Query Log) registrará todas las consultas SQL que se ejecuten en el servidor. Para activarlo debemos especificar la ruta del log mediante –general_log_file= (MySQL 5.1.29+). También podemos activarlo y desactivarlo a tiempo real desde la shell MySQL del siguiente modo:

mysql> SET GLOBAL general_log = 'OFF';
mysql> SET GLOBAL general_log = 'ON';

MySQL Query Analyzer

Si pese a las opciones anteriores seguís sin poder detectar las consultas SQL problemáticas y optimizarlas, quizás MySQL Query Analyzer sea una opción factible. Es un software de pago perteneciente a la versión Enterprise que de forma gráfica monitoriza las consultas SQL del servidor y detecta el origen de los problemas. A mi entender, las otras opciones deberían ser suficiente (junto con buenos conocimientos de DBA todo sea dicho) para detectar y solucionar cualquier problema que se presente.

 

Como habréis podido observar, la combinación de estas opciones en distintos ordenes nos permitirá arreglar muchos problemas con consultas SQL, primero detectamos los problemas con los logs de slow_queries o SHOW PROCESSLIST y después optimizamos con EXPLAIN las consultas detectadas en los pasos anteriores.

MySQL tools: benchmarking con mysqlslap


MySQLMySQL, a partir de la versión 5.1 integra una utilidad llamada mysqlslap que permite estresar y hacer benchmarking del servidor MySQL. Gracias a mysqlslap podremos comparar el rendimiento del servidor ante cambios realizados en las bases de datos, motores de almacenamiento y configuraciones así como con X número de clientes interactuando con las bases de datos, cierto tipo de consultas SQL, etc.

Si queremos comenzar haciendo tests básicos podemos dejar que sea la propia utilidad la que genere de forma aleatoria las consultas SQL, únicamente tenemos que especificar el usuario MySQL con el cual se van a realizar:

$ mysqlslap -u foo -pxxxx --auto-generate-sql
Benchmark
	Average number of seconds to run all queries: 0.007 seconds
	Minimum number of seconds to run all queries: 0.007 seconds
	Maximum number of seconds to run all queries: 0.007 seconds
	Number of clients running queries: 1
	Average number of queries per client: 0

En este test se ha realizado la conexión de un único usuario (foo) que ha realizado pruebas aleatorias entre las que se incluye la creación de una tabla, la inserción y consulta de datos en ella y la eliminación de la tabla. Si queréis ver con detalle cada una de las consultas que se realizan en el test podéis añadir la cantidad de verbose con el parámetro -v (a más v más verbose):

$ mysqlslap -vvv -u foo -pxxxx --auto-generate-sql

Estos test realmente no sirven de mucho, así que conviene saber como personalizarlos, añadir más usuarios concurrentes en las pruebas y consultas SQL personalizadas. El número de usuarios concurrentes se especifica con el parámetro

--concurrency=

, vamos a realizar la misma prueba pero con 50 usuarios concurrentes:

$ mysqlslap -u foo -pxxxx --concurrency=50 --auto-generate-sql
Benchmark
	Average number of seconds to run all queries: 0.389 seconds
	Minimum number of seconds to run all queries: 0.389 seconds
	Maximum number of seconds to run all queries: 0.389 seconds
	Number of clients running queries: 50
	Average number of queries per client: 0

Otro parámetro interesante es

--iterations=

, mediante el cual podemos especificar el número de veces que se repetirá el test. Vamos a ejecutarlo 4 veces:

$ mysqlslap -u foo -pxxxx --concurrency=50 >--iterations=4 --auto-generate-sql
Benchmark
	Average number of seconds to run all queries: 0.389 seconds
	Minimum number of seconds to run all queries: 0.389 seconds
	Maximum number of seconds to run all queries: 0.389 seconds
	Number of clients running queries: 50
	Average number of queries per client: 0

También podemos modificar el número de consultas a realizar en el test con el parámetro

--number-of-queries=

, serán repartidas entre el número de usuarios que ejecutan el test:

$ mysqlslap -u foo -pxxxx --concurrency=50 >--iterations=4 --number-of-queries=300 --auto-generate-sql
Benchmark
	Average number of seconds to run all queries: 0.233 seconds
	Minimum number of seconds to run all queries: 0.217 seconds
	Maximum number of seconds to run all queries: 0.242 seconds
	Number of clients running queries: 50
	Average number of queries per client: 6

Otro parámetro de extrema utilidad es

--engine=

, que nos permite especificar el tipo de motor a utilizar para la creación de la tabla (MyISAM, Innodb…) y así poder realizar varios tests y verificar cual es el más adecuado.

$ mysqlslap -u foo -pxxxx --concurrency=50 --iterations=4 --number-of-queries=300 --engine=innodb --auto-generate-sql
Benchmark
	Running for engine innodb
	Average number of seconds to run all queries: 1.873 seconds
	Minimum number of seconds to run all queries: 1.724 seconds
	Maximum number of seconds to run all queries: 2.197 seconds
	Number of clients running queries: 50
	Average number of queries per client: 6

Para poder personalizar al máximo el test de benchmarking conviene poder especificar la creación de tablas y consultas a realizar. Con

--create=

especificamos la creación de la tabla y con

--query=

la consulta a realizar. Este es el ejemplo disponible en la documentación de MySQL y el resultado de la prueba:

$ mysqlslap --delimiter=";" \
  --create="CREATE TABLE a (b int);INSERT INTO a VALUES (23)" \
  --query="SELECT * FROM a" --concurrency=50 --iterations=200
Benchmark
	Average number of seconds to run all queries: 0.038 seconds
	Minimum number of seconds to run all queries: 0.011 seconds
	Maximum number of seconds to run all queries: 0.061 seconds
	Number of clients running queries: 50
	Average number of queries per client: 1

Si no queremos introducir nuestras propias consultas SQL pero sí que queremos personalizar la creación de la tabla, podemos especificar parámetros como el número de columnas VARCHAR con

--number-char-cols

, el número de columnas INT con

--number-int-cols=

, etc.

Esta es una pequeña muestra de las posibilidades que nos brinda esta utilidad de MySQL y su gran utilidad para las pruebas de rendimiento de bases de datos en entornos de desarrollo y pre-producción. Si queréis profundizar más en las posibilidades de mysqlslap os recomiendo revisar la documentación de MySQL.

Optimización de WordPress (III): los Plugins


Siguiendo con los artículos de optimización de WordPress voy a indicar los que a mi parecer son los plugins más importantes en WordPress.

Hay que tener en cuenta que los plugins suelen ser el principal problema de utilización de recursos en WP, así que cuantos menos tengamos, mejor. Por eso conviene escoger con mucho cuidado los plugins a utilizar. Estos son los que personalmente recomiendo:

  • Clean Options Limpia de la base de datos restos de plugins antiguos y registros innecesarios en la tabla options, una de las más importantes de WP y que afectan directamente al rendimiento del sitio.
  • WP-Optimize: Permite optimizar la base de datos con un solo click así como eliminar revisiones de entradas y cambiar el nombre de usuario admin por uno personalizado.
  • WP Super Cache: Sin duda alguna el plugin más importante que existe en WordPress para sitios con una cantidad importante de visitas.
  • Akismet: Este plugin ya viene por defecto en WP y permite que tu blog no se llene de comentarios SPAM.

En relación con optimización estos son los cuatro plugins esenciales (a mi parecer). Por supuesto para otros objetivos como el SEO habría que seleccionar algún plugin más (WordPress Related Posts, All in One SEO Pack…).

Artículos anteriores sobre optimización de WordPress:

Optimización de WordPress: las cabeceras, fichero header.php

Optimización de WordPress: el fichero .htaccess

Optimización de WordPress (II): el fichero .htaccess


El fichero oculto .htaccess se utiliza en servidores web Apache, se encuentra en la raíz de nuestro sitio web y en él podemos configurar una serie de directivas de Apache sin necesidad de ser configuradas a nivel global en el servidor.

Entre otras cosas, podemos configurar sistemas de autenticación, url’s amigables, compresión del sitio web, etc. Para optimizar nuestro WordPress hoy añadiremos lo siguiente en dicho fichero:

Activación de caché por Apache con los módulos mod_expires y mod_headers

Antes de nada tenéis que aseguraros que el servidor web apache bajo el que está vuestro sitio web tiene compilados los módulos mod_expires y mod_headers.

El funcionamiento de este sistema es que podemos decir al navegador de la gente que visita nuestra web que ciertos ficheros (normalmente imagenes, css, javascript, etc) pueden ser cacheados durante un tiempo determinado. Si añadís el siguiente código al fichero .htaccess le diréis a los navegadores que cacheen durante un mes esos ficheros. Esto supone que la segunda vez que esta persona acceda a vuestra página no tendrá que volver a descargar las imágenes, css, javascript, etc lo que implica menor uso de transferencia de datos y mayor velocidad en el acceso web:

ExpiresActive On
ExpiresDefault A0
# expiracion de 1 mes para archivos estaticos
<FilesMatch "\.(gif|jpg|jpeg|png|swf|js|css|ico)$">
ExpiresDefault "access plus 1 months"
</FilesMatch>

Activación de compresión por Apache con el módulo mod_deflate

El módulo de Apache (apache 2) mod_deflate permite que el contenido que el servidor proporciona al cliente final (usuario) sea comprimido antes de ser enviado a través de la red. Esto supone que el tamaño de los datos enviados será mucho menor y por consiguiente la carga será más rápida. Hay que tener en cuenta que en ciertos servidores y ciertos tipos de web la activación de este sistema puede hacer que el uso de recursos en el servidor aumente así que conviene probarlo con cautela.

Para activarlo tendríais que añadir lo siguiente a vuestro fichero .htaccess, veréis que le decimos que sirva comprimidos los ficheros html, css y javascript:

# BEGIN GZIP
<ifmodule mod_deflate.c>
AddOutputFilterByType DEFLATE text/text text/html text/plain text/xml text/css application/x-javascript application/javascript
</ifmodule>
# END GZIP

Enlace al artículo anterior:

Optimización de WordPress: las cabeceras, fichero header.php

Optimización de WordPress (I): el fichero header.php


En esta serie de artículos intentaré ofrecer unos cuantos consejos para optimizar en la medida de lo posible aquellos blogs que utilizan WordPress.

Uno de los puntos flojos de WordPress es su excesivo uso de cpu, memoria y recursos de servidor en general, sobre todo con la inclusión de plugins, temas, etc. En este artículo vamos a empezar optimizando el fichero que genera la cabecera HTML del blog, header.php.

El objetivo de estos cambios es reducir el número de consultas MySQL y ejecución de llamadas PHP al servidor, haciendo lo más estática posible la cabecera de nuestro blog. Para ello, evitaremos que se llame a la base de datos para buscar el nombre del blog, la ubicación de los css, javascript o feed.

Lo primero que debemos hacer es encontrar el fichero header.php, que se encontrará en la carpeta del tema que usemos. Los temas están en la ruta “/wp-content/themes/”, en nuestro caso vamos a trabajar con un tema que se llama stardust, así que la ruta del fichero header.php es:

/wp-content/themes/stardust/header.php

Comenzamos con las modificaciones, empezamos configurando el título del blog de forma estática, eliminando la llamada php, que lo busca en la base de datos MySQL:

Antes:

<title><?php bloginfo('name'); ?><?php wp_title(); ?></title>

Después:

<title>Este es el título de mi blog</title>

Cambiamos también las declaraciones meta y el charset de la página, que siempre será igual (aunque no sepáis para que sirve, es seguro hacer este cambio):

Antes:

<meta http-equiv="Content-Type" content="<?php bloginfo('html_type'); ?>; charset=<?php bloginfo('charset'); ?>" />

Después:

<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />

La siguiente línea la podemos eliminar directamente:

<meta name="generator" content="WordPress <?php bloginfo('version'); ?>" /> <!-- leave this for stats please -->

Las llamadas a las rutas de los ficheros de estilos css también podemos configurarlas directamente:

Antes:

<link rel="stylesheet" type="text/css" href="<?php bloginfo('stylesheet_url'); ?>" media="screen" />

Después:

<link rel="stylesheet" type="text/css" href="/wp-content/themes/stardust/style.css" media="screen" />

Nota: Si no sabéis la ruta exacta al fichero css, podéis buscarlo por FTP (se llama style.css) dentro de la carpeta de vuestro tema o en el navegador pulsar Ctrl+U para ver el código fuente y buscar la línea anterior.

También podemos llamar de forma estática al fichero favicon.ico, que es el icono de favoritos y la página:

Antes:

<link rel="shortcut icon" href="<?php bloginfo('template_url'); ?>/favicon.ico" />

Después:

<link rel="shortcut icon" href="/wp-content/themes/stardust/favicon.ico" />

La URL para los pingback va a ser siempre la misma, con lo que también podemos modificara:

Antes:

<link rel="pingback" href="<?php bloginfo('pingback_url'); ?>" />

Después (cambiad miblog.es por vuestro blog):

<link rel="pingback" href="http://miblog.es/xmlrpc.php" />

También podemos configurar como estáticas las rutas a los ficheros javascript que utilicemos en el blog. Esto depende de cada blog y la ruta en la que estén, para orientaros, será algo así:

Antes:

<script type="text/javascript" src="<?php bloginfo('template_url'); ?>/js/miscript.js"></script>

Después:

<script type="text/javascript" src="/wp-content/themes/stardust/js/miscript.js"></script>

Con estos cambios hemos reducido drásticamente las llamadas php/mysql al servidor y por consiguiente aligerado en gran medida la rapidez de carga de nuestra web y su uso de recursos. Hay que tener en cuenta que cada tema puede variar y tener diferentes llamadas php, es cuestión de retocar la cabecera investigando el fichero según sus necesidades.

Optimización de un sitio web con Firebug


firebug

Probablemente no sea el más indicado para hablar sobre esta extensión de Firefox ya que apenas llevo unos días utilizándola, pero me ha dejado tan impresionado que por lo menos intentaré dar unas pinceladas de todas las posibilidades que nos ofrece.

Firebug es una herramienta imprescindible para desarrolladores web, diseñadores y webmasters. En pocas palabras, permite depurar, optimizar y eliminar fallos de la programación y estructuración de una página web y todos los elementos que la componen (javascript, html, css, imágenes…). Todo ello gracias a detallados informes, sugerencias, visores de código, etc.

Las características más importantes que he encontrado en este poco tiempo han sido:

  • Edición a tiempo real del código de la página web:
    Podemos modificar directamente desde el navegador el código HTML del sitio web, el CSS o JavaScript sin tener que tocar el código original. Ideal para probar cambios sin alterar ni una línea de código de nuestra web.
  • Analizador de rendimiento (Page Speed):
    La sección a la que más partido he sacado, muestra un informe exhaustivo de la carga de una página web, entre otras cosas podemos ver (en otros post ya hablaré sobre como maximizar la optimización de cada punto):

    • Nivel de optimización de caché a nivel de navegador (Expiración de cabeceras, etc).
    • Peticiones DNS externa (llamadas a objetos externos a nuestro sitio web)
    • Eficiencia de CSS, JavaScript, HTML, etc (No solo te indica en que puntos mejorar, sino que te ofrece la descarga del código optimizado).
    • Niveles de compresión: Indica el % de compresión que podemos aumentar, así mismo ofrece la descarga de css, javascript y html con un nivel de compresión mejorado.
    • Optimización de imágenes: Indica el % de optimización de imagenes disponible, con la descarga a cada una de las imagenes ya optimizadas. Este punto es espectacular, reduce considerablemente el peso de las imagenes sin perder un ápice de calidad.
    • Optimización de estructura de HTML.Y muchas opciones más que todavía no he tenido la opción de descubrir…
  • Informes sobre los niveles de latencia en las peticiones web, peso de cada petición, tiempo de carga total y parcial del sitio web y sus objetos
    Informe firebug
  • Consola de errores y depuración

Esto es lo que he podido “trastear” durante este par de días con la herramienta, seguro que algunos de vosotros (programadores y desarrolladores) lleváis años trabajando con ella, así que si tenéis alguna mención especial a alguna utilidad de la misma será bienvenida.

Descarga Firebug: getfirebug.com

Firebug en acción:

atime, noatime y relatime


disco duroAtime, noatime y relatime son atributos que se pueden asignar a los sistemas de ficheros, directorios o ficheros en Linux y que definen el registro de los accesos a los ficheros/directorios.

Cuando un sistema de ficheros está montado con el atributo atime (en muchas distribuciones por defecto), significa que cada vez que se acceda a un fichero o directorio, se realizará una escritura en el disco para guardar la fecha del último acceso al mismo. Esto implica un aumento considerable de I/O en la máquina y hay sistemas en los que puede conllevar una degradación del servicio bastante elevada. Por este motivo, muchas veces se recurre a deshabilitar este atributo, para ello debemos montar el sistema de fichero con noatime.

Existe otro atributo que se encuentra a mitad de camino entre atime y noatime, se trata de relatime (Ubuntu por ejemplo ya lo usa por defecto).  Relatime reduce considerablemente el refresco de la fecha de acceso ya que únicamente se modifica si el valor actual de atime es menor que la fecha de modificación del fichero. Esto es útil en el caso de que utilicemos aplicaciones que hagan uso del valor atime para ciertas tareas.

Entrando en la parte práctica, haremos uso del fichero fstab (/etc/fstab), que es donde se listan los discos y particiones del sistema, para modificar este parámetro. Únicamente tendríamos que añadir en la sección de atributos (4ª columna) nuestra selección, en este caso relatime:

/dev/sda3  /              ext4         relatime,errors=remount-ro  0  1

Posteriormente si queremos activar esta modificación, remontamos la partición, en este caso /

# mount -o remount /

Y ya deberíamos visualizar los atributos del sistema de ficheros actualizados:

$ mount
/dev/sda3 on / type ext4 (rw,relatime,errors=remount-ro)

Otro ejemplo, en este caso como noatime en /etc/fstab:

UUID=8d76759b-8949-46d1-9dd6-eec549960ff0 /datos ext3 _netdev,rw,noatime 0 0

Conviene recordar también que podemos asignar estos atributos de forma independiente a ficheros o directorios, no tiene porque ser al sistema de ficheros completo:

# chattr +A fichero

De este modo hemos deshabilitado atime para el fichero. Si no manejáis el comando chattr os recomiendo revisar esta otra entrada. Chattr y lsattr: visualizar y modificar atributos en sistemas de ficheros Linux

MySQL Query Cache: configuración y optimización


Query Cache” es una de las funcionalidades más interesantes que ofrece MySQL. A grandes rasgos, Query cache almacena en memoria el contenido y resultado de una consulta tipo SELECT, de modo que cuando un cliente vuelva a ejecutar la misma consulta (tiene que ser exactamente la misma), esta no tendrá que procesarse y se servirá directamente de la memoria sin necesidad de utilizar recursos de MySQL.

Según esta explicación, lo primero que viene a la mente es que la Query Cache será efectiva en bases de datos en las que las tablas no tienen demasiados cambios y predominan los SELECT frente a los INSERT. Vamos a explicar de forma sencilla como activar la caché y revisar sus resultados. Recomiendo leer la documentación de MySQL para quien quiera profundizar en el tema.

Lo primero que debemos hacer para activar la caché de consultas es indicarlo en el fichero de configuración my.cnf, a través de la directiva

query_cache_type

, que acepta tres valores:

Query Caché desactivada:

query_cache_type = 0

Query Caché activada:

query_cache_type = 1

Query Caché activada según demanda (especificandolo en la consulta (SELECT /* SQL_CACHE */):

query_cache_type = 2

En nuestro caso la activamos con el parámetro “1″, podemos ver el estado actual desde la shell MySQL:

mysql> select @@query_cache_type;
+--------------------+
| @@query_cache_type |
+--------------------+
| ON                 |
+--------------------+
1 row in set (0.00 sec)

Una vez activada, tenemos que asignar un tamaño de memoria disponible para el almacenamiento de estas consultas. En la mayoría de los casos con un valor menor de 100M debería ser suficiente. En el fichero my.cnf tenemos:

query_cache_size=28M

Bien, con estos dos parámetros configurados ya empezaría a utilizarse la Query Cache en nuestro servidor MySQL. Pasado un tiempo debería llegar el momento de comprobar los resultados y verificar si está siendo efectiva. Para ello, revisamos el estado de Query Cache directamente desde la shell MySQL:

mysql> show status like 'Qcache%';
+-------------------------+-----------+
| Variable_name           | Value     |
+-------------------------+-----------+
| Qcache_free_blocks      | 2319      |
| Qcache_free_memory      | 7119040   |
| Qcache_hits             | 143073915 |
| Qcache_inserts          | 67474731  |
| Qcache_lowmem_prunes    | 9384509   |
| Qcache_not_cached       | 71545921  |
| Qcache_queries_in_cache | 7528      |
| Qcache_total_blocks     | 17974     |
+-------------------------+-----------+
8 rows in set (0.00 sec)

La explicación de cada variable es la siguiente:

  • Qcache_free_blocks: El número de bloques de memoria disponibles en la query cache.
  • Qcache_free_memory: La cantidad de memoria libre en la query cache.
  • Qcache_hits: El número de aciertos de la query caché (consultas servidas desde la cache).
  • Qcache_inserts: El número de consultas insertadas a la cache.
  • Qcache_lowmem_prunes: El número de consultas eliminadas de la cache por falta de memoria disponible.
  • Qcache_not_cached: Número de consultas que no se han podido cachear.
  • Qcache_queries_in_cache: Número de consultas registradas en la cache.
  • Qcache_total_blocks: Número de bloques en la cache.

De estos puntos, conviene tener en cuenta que si el valor de Qcache_free_blocks es muy alto significa que hay fragmentación en la cache y conviene ejecutar FLUSH QUERY CACHE para desfragmentar (esto no elimina la cache). La eficiencia de la cache se mide mediante esta fórmula: Qcache_hits/(Com_select+Qcache_hits), evidentemente un número alto de hits y un buen ratio respecto a los Com_select (número total de consultas SELECT ejecutadas) es lo óptimo. Podéis ver el número de selects globales del siguiente modo:

mysql> show global status like 'Com_select%';
+---------------+----------+
| Variable_name | Value    |
+---------------+----------+
| Com_select    | 71742078 |
+---------------+----------+
1 row in set (0.00 sec)

Para comenzar a trastear con la Query Cache de MySQL esto puede ser suficiente, para el que quiera profundizar puede hacerlo revisando toda la documentación disponible de MySQL del enlace anterior.