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

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

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.

MySQL Cluster (I): Instalación de nodos de datos/SQL y gestión (MGM)

Esta es la primera parte de una serie de artículos en los que aprenderemos a montar, configurar y gestionar un cluster MySQL básico. En este caso utilizaremos dos nodos de datos, dos nodos SQL y un nodo de gestión.

Hay varias formas de instalar cada uno de los nodos, ya sea con gestores de paquetes de las distribuciones (apt, yum, .deb, rpm), compilando desde el código fuente o con los paquetes binarios. En este caso vamos a utilizar los paquetes binarios por su sencillez de instalación, cada cual puede escoger la forma que estime oportuna y según sus necesidades.

No voy a detenerme a explicar como funciona un cluster MySQL en profundidad, podéis ver toda la documentación del sitio web de MySQL donde está todo perféctamente explicado (esta guía está basada en esa documentación). Simplemente explicaré las partes (nodos) que van a componer este cluster.

  • Nodos de datos: Son los nodos encargados de almacenar los datos del cluster. Cada nodo será una máquina física independiente. Tal y como indica la documentación de MySQL hay tantos nodos de datos como réplicas, multiplicado por el número de fragmentos. Por ejemplo, con dos réplicas, cada uno teniendo dos fragmentos, necesita cuatro nodos de datos. Es recomendable revisar bien la documentación oficial de MySQL para entender el concepto y las diferentes configuraciones posibles.
  • Nodos SQL: Son los nodos que serán usados para acceder a los datos que almacenan los nodos de datos, básicamente es un servidor MySQL estandar pero que utiliza el motor de almacenamiento NDBCLUSTER.
  • Nodo de gestión: También llamado nodo MGM, es el encargado de gestionar todos los nodos del cluster, entre sus funciones encontramos las de arrancar y parar nodos, aplicar configuraciones, efectuar copias de seguridad, etc.

Instalación de nodos de datos y SQL

La instalación de un nodo de datos y un nodo SQL es igual, lo único que cambia es a posteriori la configuración y modo de arranque de cada uno de ellos (lo explicaré en el siguiente artículo) .Podéis descargar el paquete binario al igual que los demás a través de este enlace:

http://dev.mysql.com/downloads/cluster/

En este caso “Generic Linux (glibc 2.3) (x86, 32-bit), Compressed TAR Archive”:

# wget http://dev.mysql.com/get/Downloads/MySQL-Cluster-7.1/mysql-cluster-gpl-7.1.3-linux-i686-glibc23.tar.gz/from/http://gd.tuwien.ac.at/db/mysql/

Procedemos a crear el usuario y grupo de sistema para ejecutar MySQL:

# groupadd mysql
# useradd -g mysql mysql

Descomprimimos el paquete y posteriormente lo renombramos a “mysql”, ubicandolo en /usr/local/:

# tar -C /usr/local -xzvf mysql-cluster-gpl-7.0.15-linux-i686-glibc23.tar.gz
# mv /usr/local/mysql-cluster-gpl-7.0.15-linux-i686-glibc23.tar.gz /usr/local/mysql

Nos dirigimos a la ruta correspondiente y ejecutamos el script preparado para crear las bases de datos de sistema:

# cd /usr/local/mysql
# scripts/mysql_install_db --user=mysql --basedir=/usr/local/mysql

Aplicamos los permisos correspondientes a las carpetas MySQL:

# cd /usr/local/mysql
# chown -R root .
# chown -R mysql data
# chgrp -R mysql .

Nota: /usr/local/mysql/data es la ruta que utilizaremos en todos los nodos para guardar los datos

Finalmente copiamos el script de arranque de MySQL a init.d, le permitimos ejecución y lo añadimos al runlevel correspondiente:

# cp support-files/mysql.server /etc/rc.d/init.d/
# chmod +x /etc/init.d/mysql.server
# chkconfig --add mysql.server

Nota: chkconfig solo funcionará en sistemas Red-Hat y derivados.

Bien, ya tenemos el nodo primer nodo de datos ó SQL instalado. Habría que repetir esta tarea en todas las máquinas que quisieramos utilizar como nodo de datos o nodo SQL.

MANAGEMENT ndb_mgm

La instalación del nodo de gestión es extremadamente sencilla. Tenemos que descargar el mismo paquete que para los nodos de datos y SQL, descomprimirlo en una ruta temporal y copiar los ejecutables correspondientes:

# cd mysql-5.1.44-ndb-7.0.15-linux-i686-glibc23
# cp bin/ndb_mgm* /usr/local/bin
# cd /usr/local/bin
# chmod +x ndb_mgm*

En el próximo artículo comenzaremos a tocar las configuraciones de los nodos de datos, gestión y mysqld. Entonces podremos arrancar el cluster y empezar a hacer las pruebas correspondientes.

Clonar una tabla MySQL de forma rápida y sencilla

Si dispones de acceso a la shell mysql, una forma sencilla de clonar una tabla de una base de datos, tanto su estructura como contenido es la siguiente:

mysql> CREATE TABLE tabla_destino SELECT * FROM tabla_origen;

Mysqldump: excluir una tabla en el backup

Si queremos hacer un backup de una base de datos MySQL excluyendo una o varias tablas del mismo, simplemente tenemos que usar el parámetro –ignore-table=bd.tabla. Unos ejemplos:

Hacemos un backup de la base de datos test excluyendo la tabla prueba1:

mysqldump --ignore-table=test.prueba1 test > test.sql 

Hacemos un backup de la base de datos test excluyendo las tablas prueba1 y prueba2:

mysqldump --ignore-table=test.prueba1 --ignore-table=test.prueba2 test > test.sql

Esta opción también puede utilizarse para ignorar vistas (views)

MySQL: Cambiar valor de variable ft_min_word_len

Una entrada rápida, para cambiar el valor de la variable ft_min_word_len de MySQL, hay que editar al fichero de configuración (my.cnf en Unix y my.ini en Windows) y añadir el siguiente parámetro:

ft_min_word_len = X

Donde X es el valor (nº entero) que queráis asignar. Por defecto creo que está a 4:

mysql> SHOW VARIABLES LIKE 'ft_min_word_len';
+-----------------+-------+
| Variable_name   | Value |
+-----------------+-------+
| ft_min_word_len | 4     |
+-----------------+-------+
1 row in set (0.00 sec)

Posteriormente reiniciamos el servicio MySQL y listo.

MySQL: Conectar al servidor sin escribir el password

A través del fichero de configuración MySQL my.cnf (Linux) my.ini (Windows) podemos establecer ciertas directivas que se aplicarán a los clientes que se conecten al servicio MySQL. Estas directivas han de configurarse dentro de la sección [client].

Antes de nada, hay que asegurarse que el fichero my.cnf solamente tenga lectura y escritura para el propietario:

-rw------- 1 root root 310 may 26  2008 my.cnf

Algo muy interesante y que nos ahorra tiempo es la opción de configurar que cuando nos conectamos como cliente al servidor MySQL no nos pida contraseña, para ello añadimos las siguientes opciones en la sección [client] del my.cnf:

[client]
user = my_user
password = my_password
port = 3306
host = localhost

Simplemente estableced el usuario, la clave, el puerto y el host desde el que queréis conectaros (en mi caso en local), reiniciad el servicio SQL y ya podréis acceder sin escribir la clave al cliente MySQL, ejemplo:

# mysql
Welcome to the MySQL monitor.  Commands end with ; or \g.
Your MySQL connection id is 7496
Server version: 5.0.81-community MySQL Community Edition (GPL)

Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.
mysql>

Otra forma es creando un fichero en nuestra $HOME con el nombre .my.cnf y que contenga estas directivas:

# cat /root/.my.cnf
[client]
user="xxxx"
pass="xxxx"

MySQL Sandbox, uno o más servidores MySQL aislados en una máquina

MySQL SandboxMySQL Sandbox es una herramienta de gran utilidad para probar nuevas versiones de MySQL en servidores de desarrollo y pruebas. Te permite, de una forma extremadamente sencilla instalar uno o más servidores MySQL en un servidor en escasos segundos. Estos servidores MySQL están completamente aislados de cualquier otro servidor MySQL que haya instalado en el servidor, algo muy útil para probar versiones distintas de MySQL sin afectar al servidor en producción.

Por defecto, la herramienta trae opciones preestablecidas para la creación de varios servidores MySQL independientes con una única orden, creación de sistemas de replicación, creación a partir de código fuente, binarios, etc.

La instalación de MySQL Sandbox es sencilla, podemos descargarnos el tarball y seguir los pasos de la instalación o descargarlo directamente desde CPAN como módulo de Perl:

# cpan

cpan shell -- CPAN exploration and modules installation (v1.9205)
ReadLine support available (maybe install Bundle::CPAN or Bundle::CPANxxl?)

cpan> install MySQL::Sandbox

Una vez instalado, hemos de revisar las opciones de creación:

$ sandbox
The MySQL Sandbox,  version 3.0.04
(C) 2006,2007,2008,2009 Giuseppe Maxia
available applications:
make_sandbox                  : the easiest way of creating a sandbox
low_level_make_sandbox        : create a single sandbox, with fine tuning options (don't use directly)
make_replication_sandbox      : creates a sandbox with replicated master and slaves or circular
make_multiple_sandbox         : creates a group of sandboxes with the same version
make_multiple_custom_sandbox  : create a group of sandboxes with different versions
make_sandbox_from_source      : create a sandbox from a build directory
make_sandbox_from_installed   : create a sandbox from already installed binaries
sbtool                        : performs auxiliary actions with existing sandboxes

Para crear una instancia de servidor MySQL básica, simplemente tenemos que descargarnos la versión que queramos de MySQL. Vamos a crear por ejemplo una sandbox de la versión 5.4.1:

wget http://dev.mysql.com/get/Downloads/MySQL-5.4/mysql-5.4.1-beta-linux-i686-glibc23.tar.gz/from/http://mysql.rediris.es/

Una vez descargado, la forma más sencilla de crear la sandbox con MySQL 5.4.1 es la siguiente:

$ make_sandbox mysql-5.4.1-beta-linux-i686-glibc23.tar.gz
unpacking /home/alex/mysql-5.4.1-beta-linux-i686-glibc23.tar.gz
Executing low_level_make_sandbox --basedir=/home/alex/5.4.1 \
	--sandbox_directory=msb_5_4_1 \
	--install_version=5.4 \
	--sandbox_port=5410 \
	--no_ver_after_name \
	--my_clause=log-error=msandbox.err
    The MySQL Sandbox,  version 3.0.04
    (C) 2006,2007,2008,2009 Giuseppe Maxia
installing with the following parameters:
upper_directory                = /home/alex/sandboxes
sandbox_directory              = msb_5_4_1
sandbox_port                   = 5410
check_port                     = 0
no_check_port                  = 0
datadir_from                   = script
install_version                = 5.4
basedir                        = /home/alex/5.4.1
my_file                        =
operating_system_user          = alex
db_user                        = msandbox
db_password                    = msandbox
my_clause                      = log-error=msandbox.err
prompt_prefix                  = mysql
prompt_body                    =  [\h] {\u} (\d) > '
force                          = 0
no_ver_after_name              = 1
verbose                        = 0
load_grants                    = 1
no_load_grants                 = 0
no_show                        = 0
do you agree? ([Y],n) Y
090716 19:46:44 [Warning] Forcing shutdown of 2 plugins
090716 19:46:44 [Warning] Forcing shutdown of 2 plugins
loading grants
.................. sandbox server started
Your sandbox server was installed in $HOME/sandboxes/msb_5_4_1

Simplemente hay que ejecutar la orden que queramos seguida del fichero tarball que contiene la versión MySQL a instalar (podríamos hacer una sandbox sencilla como este caso, o crear replicaciones, etc). Como véis, antes de instalarla y arrancarla nos pide confirmación e informa del lugar en el que instala todas las sandboxes, la carpeta en la que se alojará la versión que estamos instalando, etc.

Dentro de la carpeta “sandboxes”, encontraréis todos los scripts necesarios para arrancar, parar y realizar acciones con las sandboxes, además de las carpetas que contienen cada una de ellas:

rwxr-xr-x 1 alex alex 2,1K 2009-07-16 19:46 sandbox_action
-rwxr-xr-x 1 alex alex   57 2009-07-16 19:46 use_all
-rwxr-xr-x 1 alex alex   58 2009-07-16 19:46 stop_all
-rwxr-xr-x 1 alex alex   59 2009-07-16 19:46 start_all
-rwxr-xr-x 1 alex alex   63 2009-07-16 19:46 send_kill_all
-rwxr-xr-x 1 alex alex   61 2009-07-16 19:46 restart_all
-rwxr-xr-x 1 alex alex   59 2009-07-16 19:46 clear_all
drwxr-xr-x 3 alex alex 4,0K 2009-07-16 19:46 msb_5_4_1

Dentro de las carpetas de cada sandbox, podéis hacer las mismas acciones pero únicamente para dicha sandbox:

:~/sandboxes/msb_5_4_1$ l
total 60K
-rwxr-xr-x 1 alex alex 1,5K 2009-07-16 19:46 stop
-rwxr-xr-x 1 alex alex 1,8K 2009-07-16 19:46 start
-rwxr-xr-x 1 alex alex 1,4K 2009-07-16 19:46 send_kill
-rwxr-xr-x 1 alex alex  881 2009-07-16 19:46 restart
-rw-r--r-- 1 alex alex 1,6K 2009-07-16 19:46 my.sandbox.cnf
-rwxr-xr-x 1 alex alex  917 2009-07-16 19:46 load_grants
-rwxr-xr-x 1 alex alex 1,7K 2009-07-16 19:46 clear
-rw-r--r-- 1 alex alex   51 2009-07-16 19:46 USING
-rwxr-xr-x 1 alex alex 1,3K 2009-07-16 19:46 use
-rwxr-xr-x 1 alex alex  923 2009-07-16 19:46 proxy_start
-rwxr-xr-x 1 alex alex 1,8K 2009-07-16 19:46 my
-rw-r--r-- 1 alex alex  187 2009-07-16 19:46 grants.mysql
-rwxr-xr-x 1 alex alex 1,5K 2009-07-16 19:46 change_ports
-rwxr-xr-x 1 alex alex 1,7K 2009-07-16 19:46 change_paths
drwx------ 4 alex alex 4,0K 2009-07-16 19:47 data

con el comando “use” podemos acceder al cliente MySQL para gestionar la sandbox:

~/sandboxes/msb_5_4_1$ ./use
Welcome to the MySQL monitor.  Commands end with ; or \g.
Your MySQL connection id is 2
Server version: 5.4.1-beta MySQL Community Server (GPL)

Type 'help;' or '\h' for help. Type '\c' to clear the buffer.

mysql [localhost] {msandbox} ((none)) > show databases;
+--------------------+
| Database           |
+--------------------+
| information_schema |
| mysql              |
| test               |
+--------------------+
3 rows in set (0.00 sec)

mysql [localhost] {msandbox} ((none)) >

Bien, esto es lo más básico para comenzar a utilizar esta genial herramienta, mención especial merece también el comando sbtool, que permite realizar acciones extras con las sandboxes, podéis verlas a continuación:

$ sbtool --help
usage: /usr/local/bin/sbtool [options]
	-o     --operation       (s) <> - what task to perform
		 'info'     returns configuration options from a Sandbox
		 'tree'     creates a replication tree
		 'move'     moves a Sandbox to a different location
		 'unpreserve' makes a sandbox NOT permanent
		 'range'    finds N consecutive ports not yet used by the Sandbox
		 'port'     Changes a Sandbox port
		 'copy'     copies data from one Sandbox to another
		 'ports'    lists ports used by the Sandbox
		 'delete'   removes a sandbox completely
		 'preserve' makes a sandbox permanent
	-s     --source_dir      (s) <> - source directory for move, copy, delete
	-d     --dest_dir        (s) <> - destination directory for move,copy
	-n     --new_port        (s) <> - new port while moving a sandbox
	-u     --only_used       (-) <> - for "ports" operation, shows only the used ones
	-i     --min_range       (i) <5000> - minimum port when searching for available ranges
	-x     --max_range       (i) <64000> - maximum port when searching for available ranges
	-z     --range_size      (i) <10> - size of range when searching for available port range
	-f     --format          (s)  - format for "ports" and "info"
		 'perl'     fully structured information in Perl code
		 'text'     plain text dump of requested information
	-p     --search_path     (s)  - search path for ports and info
	-a     --all_info        (-) <> - print more info for "ports" operation
	       --master_node     (i) <1> - which node should be master (default: 1)
	       --tree_nodes      (s) <> - description of the tree (x-x x x-x x|x x x|x x)
	       --mid_nodes       (s) <> - description of the middle nodes (x x x)
	       --leaf_nodes      (s) <> - description of the leaf nodes (x x|x x x|x x)
	       --tree_dir        (s) <> - which directory contains the tree nodes
	-v     --verbose         (-) <> - prints more info on some operations
	-h     --help            (-) <1> - this screen

MySQL: Volcar determinadas filas con mysqldump

Probablemente en ciertas ocasiones no necesites volcar en un fichero todo el backup de una base de datos MySQL, sino que solamente necesites volcar ciertas filas de la bbdd. Con la herramienta de backup y volcado de bases de datos mysqldump podemos hacer esta tarea de un modo sencillo.

En el siguiente ejemplo podéis observar como mediante la cláusula –where podemos especificar las condiciones que deben cumplir las filas para ser volcadas en el backup:

mysqldump -u <usuario> -p  --tables <tablas>  --where="<condición>" > dumptest.sql

Un ejemplo real de –where:

--where="user='test'"

Sencillo y muy útil en bases de datos de gran tamaño de las cuales necesitamos recuperar solamente una parte de los registros.