Script para optimizar las tablas fragmentadas en MySQL

Bueno otro buen script a la huchaca… esta escrito en bash aparte de ser utilisisimo porque chequea las tablas fragmentadas y tambien chequea todas las bbdds en busca de tablas MyISAM o INNODB y las optimiza.

#!/bin/bash

VERSION="0.7.2"
log="$PWD/mysql_error_log.txt"

echo "MySQL fragmentation finder (and fixer) v$VERSION, written by Phil Dufault ( http://www.dufault.info/ )"

showHelp() {
echo -e "\tThis script only repairs MyISAM and InnoDB tables"
echo -e "\t--help or -h\t\tthis menu"
echo -e "\t--user username\tspecify mysql username to use\n\t\t\tusing this flag means the script will ask for a password during runtime, unless you supply..."
echo -e "\t--password \"yourpassword\""
echo -e "\t--host hostname\tspecify mysql hostname to use, be it local (default) or remote"
}

#s parse arguments
while [[ $1 == -* ]]; do
case "$1" in
--help|-h) showHelp; exit 0;;
--user) mysqlUser="$2"; shift 2;;
--password) mysqlPass="$2"; shift 2;;
--host) mysqlHost="$2"; shift 2;;
--) shift; break;;
esac
done

# prevent overwriting the commandline args with the ones in .my.cnf, and check that .my.cnf exists
if [[ ! $mysqlUser && -f "$HOME/.my.cnf" ]]; then
if grep "user=" "$HOME/.my.cnf" >/dev/null 2>&1; then
if grep "pass=" "$HOME/.my.cnf" >/dev/null 2>&1; then
mysqlUser=$(grep user= < "$HOME/.my.cnf" | awk -F\" '{print $2}'); mysqlPass=$(grep pass= < "$HOME/.my.cnf" | awk -F\" '{print $2}'); if grep "host=" "$HOME/.my.cnf" >/dev/null 2>&1; then
mysqlHost=$(grep host= < "$HOME/.my.cnf" | awk -F\" '{print $2}'); fi else echo "Found no pass line in your .my.cnf,, fix this or specify with --password" fi else echo "Found no user line in your .my.cnf, fix this or specify with --user" exit 1; fi fi # set localhost if no host is set anywhere else if [[ ! $mysqlHost ]]; then mysqlHost="127.0.0.1" fi # error out if [[ ! $mysqlUser ]]; then echo "Authentication information not found as arguments, nor in $HOME/.my.cnf" echo showHelp exit 1 fi if [[ ! $mysqlPass ]]; then echo -n "Enter your MySQL password: " read -s mysqlPass fi # Test connecting to the database: mysql -u"$mysqlUser" -p"$mysqlPass" -h"$mysqlHost" --skip-column-names --batch -e "show status" >/dev/null 2>&1
if [[ $? -gt 0 ]]; then
echo "An error occured, check $log for more information.";
exit 1;
fi

# Retrieve the listing of databases:
databases=( $(mysql -u"$mysqlUser" -p"$mysqlPass" -h"$mysqlHost" --skip-column-names --batch -e "show databases;" 2>"$log") );
if [[ $? -gt 0 ]]; then
echo "An error occured, check $log for more information."
exit 1;
fi

echo -e "Found ${#databases[@]} databases";
for i in ${databases[@]}; do
# get a list of all of the tables, grep for MyISAM or InnoDB, and then sort out the fragmented tables with awk
fragmented=( $(mysql -u"$mysqlUser" -p"$mysqlPass" -h"$mysqlHost" --skip-column-names --batch -e "SHOW TABLE STATUS FROM $i;" 2>"$log" | awk '{print $1,$2,$10}' | egrep "MyISAM|InnoDB" | awk '$3 > 0' | awk '{print $1}') );
if [[ $? -gt 0 ]]; then
echo "An error occured, check $log for more information."
exit 1;
fi
tput sc
echo -n "Checking $i ... ";
if [[ ${#fragmented[@]} -gt 0 ]]; then
if [[ ${#fragmented[@]} -gt 0 ]]; then
if [[ ${#fragmented[@]} -gt 1 ]]; then
echo "found ${#fragmented[@]} fragmented tables."
else
echo "found ${#fragmented[@]} fragmented table."
fi
fi
for table in ${fragmented[@]}; do
let fraggedTables=$fraggedTables+1;
echo -ne "\tOptimizing $table ... ";
mysql -u"$mysqlUser" -p"$mysqlPass" -h"$mysqlHost" -D "$i" --skip-column-names --batch -e "optimize table $table" 2>"$log" >/dev/null
if [[ $? -gt 0 ]]; then
echo "An error occured, check $log for more information."
exit 1;
fi
echo done
done
else
tput rc
tput el
fi
unset fragmented
done

# footer message
if [[ ! $fraggedTables -gt 0 ]]; then
echo "No tables were fragmented, so no optimizing was done.";
else
if [[ $fraggedTables -gt 1 ]]; then
echo "$fraggedTables tables were fragmented, and were optimized.";
else
echo "$fraggedTables table was fragmented, and was optimized.";
fi
fi

if [[ ! -s $log ]]; then
rm -f "$log"
fi

unset fraggedTables

Link | http://www.dufault.info/blog/a-script-to-optimize-fragmented-tables-in-mysql/

Guardar el resultado de MySQL en un archivo

Simpleza de MySQL y a la misma vez útil cuando se trata de guardar resultados (de SELECT por ejemplo) bastantes grandes en MySQL.
Con tee lo que hacemos es loguear todo lo que se produce en la consola de MySQL, tanto los comandos como los resultados de estos :D, con notee paramos de escribir en el archivo que le hemos indicado antes con tee

Esto me lo apunto aqui en el blog, para ayudar a la memoria 😀

mysql>tee archivo.txt
mysql>select * from tabla;
mysql>notee

MySQL Tips

Aqui os dejo una pequeña Cheat Sheet con muchos MySQL Tips (Spaninglish owned :D)

MySQL : Crear una base de datos

Crear una base de datos:

$ mysql
mysql > show databases;
mysql > create database joomla;
mysql > use database joomla;

o bien:

$ mysqladmin create joomla

Si es necesario un encoding en particular se necesitan definir el character set y el collate:

  • En ISO:
    mysql > create database joomla character set latin1 collate
    latin1_spanish_ci;
  • En UTF8:
    mysql > create database joomla character set utf8 collate
    utf8_general_ci;

MySQL: Borrar una base de datos

Borrar bases de datos:

$ mysql
mysql > show databases;
mysql > drop database joomla;

o bien:

$ mysqladmin drop joomla

MySQL: Hacer un dump de la base de datos

$ mysqldump -h localhost -u root -p joomla > joomla.sql

donde joomla es la base de datos, root es el usuario de la base datos y localhost el servidor de la base de datos.

MySQL: Importar una base de datos

$ mysql
mysql> create database joomla;
mysql> use joomla
mysql> source joomla.sql

o bien:

$ mysql -u root -p --database=joomla < joomla.sql

MySQL: Importar tablas de una base de datos

$ mysqldump --user=root joomla jos_core_acl_aro jos_core_acl_groups_aro_map jos_users > jos_users.sql

MySQL: Importar la estructura de base de datos

$ mysqldump --no-data --user=root joomla > joomla.sql

MySQL: Vaciar una tabla

$ mysql
> use joomla;
> truncate table jos_users;

MySQL: Cómo generar los scripts individuales para las tablas de una base de datos

El script generate-mysql-tables-scripts.sh

Nota: el usuario es root y no tiene contraseña.

 ~/tmp $ cat generate-mysql-tables-scripts.sh
DATABASE=$1
for i in `echo "use $DATABASE; show tables;" | mysql -u root|grep -v "Tables_in"`
        do
                echo "Dumping $i"
                mysqldump -u root $DATABASE $i > $i.sql
        done

De este modo:

 ~/tmp $ generate-mysql-tables-scripts.sh zyf
Dumping ...
Dumping
.
.
.

MySQL: Importar una base de datos desde un fichero CSV

$ mysql
> load data local infile 'users.csv' into table `jos_users`
> fields terminated by ','
> optionally enclosed by '"'
> lines terminated by '\n\r';

Especificamos que el contenido se encuentra en el servidor, en un fichero llamado users.csv

> local infile 'users.csv'

que los campos se separan mediante comas:

> fields terminated by ','

que el contenido puede estar entrecomillado, y de ser así el contenido se pasará a la BD sin comillas (o en su defecto sin el símbolo especificado en el comando). Si quisiéramos pasar el contenido a la BD con comillas y todo, no especificaríamos esta opción.

> optionally enclosed by '"'

especificando cual es el carácter que señaliza el final de una línea, de no tener nada que marque el fin de una línea omitiríamos esta opción.

> lines terminated by '\n\r'

MySQL: Exportar a CSV una select

Desde la consola de mysql:

> select * from joomla.jos_users into outfile '/tmp/filename.csv'
fields terminated by ',' lines terminated by '\n';

o desde la terminal:

$ mysql -u root joomla -B -e \
"select \* from users " | sed 's/\t/","/g;s/^/"/;s/$/"/;s/\n//g' > filename.csv

MySQL: Cambiar la contraseña de root en mysql

A todos nos ha pasado alguna vez ir a modificar algo en nuestro servidor MySQL y encontrarnos con:

ERROR 1045: Access denied for user: 'root@localhost' (Using password: YES)

Aquí está la receta:

$ killall mysqld
$ /usr/sbin/mysqld --skip-grant-tables &
$ mysql -u root mysql
mysql> UPDATE mysql.user SET Password=PASSWORD('') WHERE User='root';
mysql> FLUSH PRIVILEGES;
mysql> EXIT
$ killall mysqld
$ /usr/sbin/mysqld &

Si se conoce la contraseña anterior sólo sería necesario:

mysql> set password for 'root'@'localhost' = password('');

o en su defecto:

$ mysql -u root mysql
mysql> UPDATE mysql.user SET Password=PASSWORD('') WHERE User='root';
mysql> FLUSH PRIVILEGES;
mysql> EXIT

MySQL: Listado de privilegios de MySQL

En la siguiente http://dev.mysql.com/doc/refman/5.0/es/privileges-provided.html página de documentación de MySQL se listan y explican en castellano todos los privilegios de MySQL.

MySQL: Dar privilegios a usuario en una base de datos

Para dar privilegios a un usuario sobre una base de datos ejecutaremos el siguiente comando, en el ejemplo le damos todos los permisos que una base de datos tiene, la sintaxis queda debajo:

$ mysql -u root -p
mysql> grant all on joomla.* to joomla identified by 'joomla';

Donde el primer joomla.* es la base de datos, el segundo el nombre de usuario y por ultimo la contraseña:

mysql> grant all on nombre_de_la_basededatos.* to nombre_usuario identified by ‘contraseña’;

Por último, actualizamos los privilegios:

mysql> flush privileges;

Ya podremos entrar en la base de datos usando el usuario y la contraseña asignada;

$ mysql -u joomla -p

Mostrar privilegios de un usuario de MySQL

mysql> show grants for usuario;

Quitar privilegios a un usuario de MySQL

mysql> revoke privilegio on basededatos.table from usuario;

Mostrar host y usuarios de MySQL

mysql> use mysql;
mysql> select host,user from user;

Eliminar un usuario de MySQL

mysql> drop user usuario;

Permitir acceso remoto a MySQL

Editar el fichero /etc/mysql/my.cnf y comentar la línea: bind-address = 127.0.0.1

vi /etc/mysql/my.cnf
# bind-address          = 127.0.0.1

Después tendríamos que crear usuarios utilizando la siguiente sentencia:

> grant all on basededatos.tabla to usuario@'dirección_ip' identified by 'contraseña';

Ejemplos

Sentencia para establecer permisos en la tabla table de la base da datos database para el usuario user desde el host de la dirección IP 192.168.10.10 con la contraseña password:

> grant all on database.table to user@'192.168.10.10' identified by 'password';

Sentencia para establecer permisos en todas las tablas de la base de datos database para el usuario user desde un host que tiene cualquier dirección IP y sin contraseña:

> grant all on database.* to user@'%';

Modificar codificación del servidor MySQL

Podemos ver la codificación de MySQL mediante el comando:

> show variables;

En este ejemplo vamos a cambiar la codificación a UTF-8. Para ello haremos lo siguiente:

$ vi /etc/mysql/my.cnf

Buscaremos la sección mysqld y después añadiremos las siguientes líneas.

And add these lines under it:

# utf8
init-connect='SET NAMES utf8'
character-set-server=utf8
collation-server=utf8_general_ci

Una vez hecho esto sólo nos queda reiniciar el servicio.

/etc/init.d/mysql stop
/etc/init.d/mysql start

Comprobar codificación de una tabla

mysql> SHOW CREATE DATABASE `prueba`;
+----------+-------------------------------------------------------------------+
| Database | Create Database                                                   |
+----------+-------------------------------------------------------------------+
| prueba   | CREATE DATABASE `prueba` /*!40100 DEFAULT CHARACTER SET latin1 */ |
+----------+-------------------------------------------------------------------+
1 row in set (0.00 sec)

Modificar codificación de una tabla

> ALTER TABLE tabla CONVERT TO CHARSET charset COLLATE collation;

Por ejemplo:

> ALTER TABLE tabla CONVERT TO CHARSET latin1 COLLATE latin1_spanish_ci;

Variables de mysql

$ mysqladmin variables
$ mysqladmin variables | grep datadir
| datadir                         | /var/lib/mysql/             |

Errores comunes

ERROR 1005 (HY000) at line 1: Can’t create table ‘./joomla/jos_users.frm’ (errno: 150)

‘Explicación:

Es un error que puede surgir al importar una base de datos.

Debe de haber algún error en la comprobación de Foreign Keys.

‘Solución:

Añadir la siguiente línea al principio del fichero .sql:

> SET FOREIGN_KEY_CHECKS = 0;

Y después la siguiente línea al final del fichero .sql:

> SET FOREIGN_KEY_CHECKS = 1;

Si sabéis o quereis saber mas pequeños tips de mysql y quereis que los añada aqui hacer un comentario y lo añado 😀

Activar la opción de trabajar con tablas vinculadas en PhpMyAdmin

PhpMyAdmin incluye opciones para relacionar tablas (de tipo InnoDB), pero muchas veces vienen desactivadas y al darle al boton operaciones en la base de datos, aparece el error: Las opciones adicionales para trabajar con tablas vinculadas fueron desactivadas. Para saber porqué, dé clic aquí.

Para activarlas debemos añadir algunas opciones a los ficheros de configuración del PMA.

En algunos paquetes que integran Apache, MySQL y PHP no es necesario configurar nada porque ya traen activadas por defecto estas opciones, comoXAMPP. En otros paquetes, aunque configures estas opciones, es posible que sigan sin funcionar las relaciones, como en el WAMP.

Para lograr que funcionen las relaciones debemos seguir estos pasos:

  1. Comprobar si tenemos una tabla llamada phpmyadmin. Si no es así, ejecutar el script create_tables.sql, que está en la carpeta de scripts de phpmyadmin.
    Esta es una tabla que usa PMA internamente para ofrecer características adicionales, como las relaciones entre tablas.
  2. Acceder al fichero de configuración de PMA config.inc.php (en las versiones nuevas viene como config.default.php) y dejar estas opciones tal y como se indica a continuación:
    $cfg['Servers'][$i]['auth_type'] = 'http';
    $cfg['Servers'][$i]['controluser'] = 'pma';
    $cfg['Servers'][$i]['controlpass'] = 'pmapass';
    $cfg['Servers'][$i]['pmadb'] = 'phpmyadmin';
    $cfg['Servers'][$i]['bookmarktable'] = 'pma_bookmark';
    $cfg['Servers'][$i]['relation'] = 'pma_relation';
    $cfg['Servers'][$i]['table_info'] = 'pma_table_info';
    $cfg['Servers'][$i]['table_coords'] = 'pma_table_coords';
    $cfg['Servers'][$i]['pdf_pages'] = 'pma_pdf_pages';
    $cfg['Servers'][$i]['column_info'] = 'pma_column_info';
    $cfg['Servers'][$i]['history'] = 'pma_history';
    $cfg['Servers'][$i]['designer_coords'] = 'pma_designer_coords';
  3. Crear un usuario MySQL para utilizar la relación entre tablas (que será el que indicamos anteriormente como controluser con la contraseña indicada en controlpass) y asignarle los correspondientes permisos:
    GRANT USAGE ON mysql.* TO 'pma'@'localhost' IDENTIFIED BY 'pmapass';
    GRANT SELECT (Host, User, Select_priv, Insert_priv, Update_priv, Delete_priv, Create_priv, Drop_priv, Reload_priv, Shutdown_priv, Process_priv, File_priv, Grant_priv, References_priv, Index_priv, Alter_priv, Show_db_priv, Super_priv, Create_tmp_table_priv, Lock_tables_priv, Execute_priv, Repl_slave_priv, Repl_client_priv) ON mysql.user TO 'pma'@'localhost';
    GRANT SELECT ON mysql.db TO 'pma'@'localhost';
    GRANT SELECT ON mysql.host TO 'pma'@'localhost';
    GRANT SELECT (Host, Db, User, Table_name, Table_priv, Column_priv) ON mysql.tables_priv TO 'pma'@'localhost';
  4. Reiniciar apache y acceder al PMA. Si todo ha salido bien, ya no tendremos el mensaje de error y aparecerá en el menú de arriba el botón diseñador, desde donde podremos establecer las relaciones entre tablas.

Más información:
PhpMyAdmin Wiki