18
0
Fork 0
wiki/HowtoMySQL.md

49 KiB
Raw Blame History

categories: databases title: Howto MySQL : installation et utilisation courante.

MySQL est une base de données très populaire au sein des infrastructures web. Nous utilisons au choix la version libre de MySQL distribuée par Oracle, et MariaDB un fork créé en 2009 par le créateur initial de MySQL.

Installation

Sous Debian 9, nous installons MariaDB :

# apt install mariadb-server mariadb-client libconfig-inifiles-perl

$ mysql --version
mysql  Ver 15.1 Distrib 10.1.26-MariaDB, for debian-linux-gnu (x86_64) using readline 5.2

Note : Sous Debian 8, nous installons la version libre de MySQL distribuée par Oracle :

# apt install mysql-server

$ mysql --version
mysql  Ver 14.14 Distrib 5.5.53, for debian-linux-gnu (x86_64) using readline 6.3

ou MariaDB :

# apt install mariadb-server-10.0

$ mysql --version
mysql  Ver 15.1 Distrib 10.0.28-MariaDB, for debian-linux-gnu (x86_64) using readline 5.2

L'installation sous Debian demande un mot de passe pour le superutilisateur (par défaut root) de MySQL. En laissant un mot de passe vide, on peut se connecter sans mot de passe :

$ mysql -u root
Welcome to the MariaDB monitor.  Commands end with ; or \g.
Your MariaDB connection id is 18348
Server version: 10.1.26-MariaDB-0+deb9u1 Debian 9.1

Copyright (c) 2000, 2017, Oracle, MariaDB Corporation Ab and others.

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

MariaDB [(none)]>

Il faut ensuite mettre un mot de passe pour le superutilisateur de MySQL, on conseille d'utiliser l'identifiant adminmysql car root peut prêter à confusion :

mysql> GRANT ALL PRIVILEGES ON *.* TO adminmysql@localhost IDENTIFIED BY 'PASSWORD' WITH GRANT OPTION;
mysql> DELETE FROM mysql.user where User='root';

Au niveau sécurité, le mot de passe est généré à l'installation (stocké dans /etc/mysql/debian.cnf lisible que par root) par la commande :

perl -e 'print map{("a".."z","A".."Z",0..9)[int(rand(62))]}(1..16)'

Enfin, on peut utiliser un fichier .my.cnf pour conserver l'identifiant et le mot de passe. Par exemple pour root, dans /root/.my.cnf :

[client]
user = adminmysql
password = PASSWORD

Pour changer le mot de passe, on fera simplement :

# mysqladmin password PASSWORD

On notera sous Debian la présence d'un utilisateur debian-sys-maint qui sert à certains scripts Debian : il ne doit pas être supprimé !

Sous Debian 8, avec MariaDB 10.0, l'utilisateur debian-sys-maint n'a pas le privilège GRANT. Il est donc impossible de créer d'autres utilisateurs en étant connecté avec ce compte.

bibliothèque client

Certains logiciels tiers nécessitent la "bibliothèque client".

Sur Debian 8, c'est le paquet libmysqlclient-dev.

Sur Debian 9 (et Debian 8 avec backports), c'est le meta-paquet default-libmysqlclient-dev qui permet de facilement installer la paquet adapté à votre base de données.

MySQL 5.7

https://dev.mysql.com/doc/mysql-apt-repo-quick-guide/

Pour installer MySQL 5.7 distribuée par Oracle sous Debian 9, on ajoute le dépôt repo.mysql.com :

# echo "deb http://repo.mysql.com/apt/debian stretch mysql-5.7" > /etc/apt/sources.list.d/mysql57.list
# apt-key adv --keyserver pgp.mit.edu --recv-keys 5072E1F5

On peut ensuite installer les paquets :

# apt install mysql-server mysql-client

Note : il faudra alors installer mytop en récupérant le package de Debian 8

Configuration

Le fichier de configuration principal est /etc/mysql/my.cnf qui inclue notamment les fichiers .cnf présents dans les sous-répertoires conf.d/ et mariadb.conf.d/.

Note : attention, si vous avez une configuration MySQL/MariaDB issue d'une Debian 8 (suite upgrade par exemple), le sous-répertoire mariadb.conf.d/ ne sera pas pris en compte.

Le fichier /etc/mysql/mariadb.conf.d/z-evolinux-defaults.cnf contient nos optimisations basiques :

[mysqld]

###### Connexions
# Maximum de connexions concurrentes (defaut = 100)... provoque un "Too many connections"
max_connections = 250
# Maximum de connexions en attente en cas de max_connections atteint (defaut = 50)
back_log = 100
# Maximum d'erreurs avant de blacklister un hote
max_connect_errors = 10
# Loguer les requetes trop longues
slow_query_log = 1
slow_query_log_file = /var/log/mysql/mysql-slow.log
long_query_time = 10

###### Tailles
# Taille reservee au buffer des index MyIsam
# A ajuster selon les resultats
key_buffer_size = 512M
# Taille max des paquets envoyés/reçus … provoque un "Packet too large"
max_allowed_packet = 64M
# Taille de la memoire reserve pour un thread
thread_stack = 192K
# A mettre le nombre de threads CPU alloues pour MySQL
thread_cache_size = 1
# Taille maximum des tables de type MEMORY
max_heap_table_size = 64M

###### Cache
# max_connections x nbre max de tables dans une jointure (defaut = 64)
table_open_cache       = 4096
table_definition_cache = 4096
# Taille max des requetes cachees (defaut = 1M)
query_cache_limit       = 8M
# Taille reservee pour le cache (defaut = 0)
query_cache_size        = 256M
# Type de requetes a cacher (defaut = 1 : tout peut etre cache)
query_cache_type        = 1
# Cache tables
max_heap_table_size     = 128M
tmp_table_size          = 128M

###### InnoDB
# Si InnoDB n'est pas utilise... le desactiver
#skip-innodb
# En general, il est plus optimum d'avoir un fichier par table
innodb_file_per_table
# Taille memoire allouee pour le cache des datas et index
# A ajuster en fonction de sa RAM (si serveur dedie a MySQL, on peut aller jusqu'a 80%)
innodb_buffer_pool_size = 512M
# Nombre maximum de threads systeme concurents
innodb_thread_concurrency = 16
# Ajuste la valeur des logs InnoDB
# (attention, il faut ensuite stopper MySQL et effacer les fichiers ib_logfile*)
#innodb_log_file_size = 128M
#innodb_log_files_in_group = 2

###### Misc
# charset utf8 par defaut
character-set-server=utf8
collation-server=utf8_general_ci
# Patch MySQL 5.5.53
secure-file-priv = ""

Note : MariaDB 10.1 avec Debian 9 est par défaut en utf8mb4 + collation utf8mb4_general_ci.

Le fichier /etc/mysql/mariadb.conf.d/zzz-evolinux-custom.cnf contient nos éventuelles optimisations spécifiques.

Nous désactivons également une protection mise en place par l'unité systemd. Cela permet d'utiliser la partition /home ou /srv pour des sauvegardes ou autres opérations :

# cat /etc/systemd/system/mariadb.service.d/evolinux.conf

[Service]
ProtectHome=false

Par défaut, MySQL écoute en réseau sur 127.0.0.1 (port TCP/3306) et sur la socket Unix /var/run/mysqld/mysqld.sock Pour activer les connexions réseau à distance, il faut ajouter la configuration suivante dans zzz-evolinux-custom.cnf :

[mysqld]
bind-address = 0.0.0.0

Selon les ressources de la machine, il faut optimiser davantage les options (par défaut, la configuration est adaptée pour une machine avec très peu de mémoire vive !).

On conseille au minimum d'ajuster thread_cache_size et innodb_buffer_pool_size :

[mysqld]
# Nombre de threads CPU alloués pour MySQL
thread_cache_size = 2
# Mémoire allouée pour le cache InnoDB (si serveur dédié, on peut aller jusqu'à 80% de la RAM)
innodb_buffer_pool_size = 2G

Pour plus d'informations sur l'optimisation avancée de MySQL, consultez le guide /HowtoMySQL/Optimize.

Note : Sous Debian 8, nous mettons notre configuration dans /etc/mysql/conf.d/evolinux.cnf

datadir / tmpdir

Par défaut, le datadir (le répertoire où sont stockées les données brutes) est /var/lib/mysql/.

Pour diverses raisons il peut être intéressant de le déplacer (partition ou disque dédié etc.).

Pour des raisons de compatibilité, on conseille de conserver un lien symbolique :

# systemctl stop mysql
# mv /var/lib/mysql /srv/mysql-datadir
# ln -s /srv/mysql-datadir /var/lib/mysql
# systemctl start mysql

Pour certaines opérations lourdes, MySQL a besoin d'un tmpdir (répertoire où il va écrire des tables temporaires). Par défaut il utilise /tmp mais vu qu'il est parfois nécessaire d'avoir plusieurs Go de libre, on pourra utiliser un répertoire différents :

[mysqld]
tmpdir = /srv/mysql-tmpdir

Logs

Sous Debian, les journaux de MySQL (démarrage, arrêt, erreurs, informations) sont envoyés via syslog. Par défaut, ils seront donc visibles dans /var/log/syslog.

Le répertoire /var/log/mysql/ contient les binlogs (trace de toutes les requêtes INSERT/UPDATE/DELETE exécutées).

Utilisation courante

Créer

Créer une nouvelle base de données nommée foo :

mysql> CREATE DATABASE foo;

Créer une table nommée bar avec différents champs :

mysql> CREATE TABLE bar (id INT not null AUTO_INCREMENT, prenom VARCHAR
(50) not null , nom VARCHAR (50) not null , ne_le DATE not null ,
ville VARCHAR (90), enfants INT, PRIMARY KEY (id));

Ajouter un champ à une table :

mysql> ALTER TABLE bar ADD another VARCHAR(100) DEFAULT NULL;

Ajouter un champ à une table en précisant sa place :

mysql> ALTER TABLE bar ADD another VARCHAR(100) DEFAULT NULL AFTER prenom;

Lister

Voir les bases de données créées :

mysql> SHOW DATABASES;

Lister les accès créés :

mysql> select Host,user from mysql.user;

Connaître les privilèges de ces derniers :

mysql> show grants for USER@'HOST';

Utiliser la base de données foo :

mysql> USE foo

Voir les tables créées :

mysql> SHOW TABLES;

Décrire une table :

mysql> DESC bar;

Sélectionner tous les champs d'une table :

mysql> SELECT * FROM bar;

Lancer des commandes bash depuis l'invite de commande :

mysql> \! ls -l
-rw-r----- 1 user user  208774 Jan 11 14:31 dump_base.sql

Lister les droits pour tous les accès MySQL créés :

# mysql -e "select concat('\'',User,'\'@\'',Host,'\'') as '' from mysql.user" | sort | \
( while read user; do [ -z "$user" ] && continue; echo "-- $user :"; mysql -e "show grants for $user"; done )

-- 'accesbase'@'localhost' :
Grants for accesbase@localhost
GRANT USAGE ON *.* TO 'accesbase'@'localhost' IDENTIFIED BY PASSWORD '*XXXX'
GRANT ALL PRIVILEGES ON `base`.* TO 'accesbase'@'localhost'
# mysql -e "select * from information_schema.user_privileges;"

Supprimer

Supprimer un champ à une table :

mysql> ALTER TABLE bar DROP another;

Effacer des données d'une table :

mysql> DELETE FROM bar WHERE nom='waddle';

Effacer TOUTES les données d'une table :

mysql> DELETE FROM bar;

Supprimer une table :

mysql> DROP TABLE bar;

Supprimer une base de données :

mysql> DROP DATABASE foo;

Supprimer les différents privilèges pour un utilisateur mysql :

mysql> REVOKE ALL PRIVILEGES ON base.* FROM 'user'@'localhost';

Lister les bases de données dont l'utilisateur à le droit d'accès:

SELECT * FROM mysql.db WHERE User="nvmpubli";

Supprimer un accès (utilisateur) :

mysql> DROP USER 'user'@'localhost';

Renommer

Base

  • Créer une base vide
  • Renommer toutes les tables vers cette dernière (utilisation script ci-dessous)
BASE_FROM=db1; BASE_TO=db2
for table in $(mysql -e "use $BASE_FROM; show tables\G;" | grep -v '^\*\*\*' | cut -d':' -f2 | sed 's/^ //'); do echo $table; mysql -e "RENAME TABLE ${BASE_FROM}.${table} TO ${BASE_TO}.${table};"; done
  • Appliquer les bons droits à la bdd

Table

Renommer un champ :

mysql> ALTER TABLE bar CHANGE COLUMN another anotherone TEXT;

Changer le type d'un champ :

mysql> ALTER TABLE bar CHANGE another another enum('foo',bar');

Insérer

Insertion de données dans une table :

mysql> INSERT INTO bar VALUES (1,'jp','papin','2005-06-12','Marseille',2);
INSERT INTO test (id,prenom,nom,ne_le) VALUES (2,'c','waddle','2004-06-17');

Vues

Lister les vues de la base foo :

mysql> SHOW FULL TABLES IN foo WHERE TABLE_TYPE LIKE 'VIEW';

Créer une vue baz à partir du contenu de la table bar :

mysql> CREATE VIEW baz AS SELECT * FROM bar;

Voir la vue :

mysql> SHOW CREATE VIEW `baz`;

Supprimer une vue baz :

mysql> DROP VIEW `baz`;

Administration

On crée une base de données et un utilisateur associé :

# mysqladmin create foo
# mysql
mysql> GRANT ALL PRIVILEGES ON foo.* TO 'jdoe'@localhost IDENTIFIED BY 'PASSWORD';

Cette opération revient à insérer des lignes suivante dans les tables mysql.user et mysql.db :

mysql> INSERT INTO mysql.user VALUES ('localhost','jdoe',password('PASSWORD'),'N','N','N','N','N','N','N','N','N','N','N','N','N','N','N','N','N','N','N','N','N','N','N','N','N','N','N','N','N','','','','',0,0,0,0,'',NULL);
mysql> INSERT INTO mysql.db VALUES ('localhost','foo','jdoe','Y','Y','Y','Y','Y','Y','N','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y');
mysql> FLUSH PRIVILEGES;

À savoir :

Pour migrer de Debian 6 à 7 :

  • 3 colonnes ont été ajoutées dans mysql.user : Create_tablespace_priv, plugin et authentication_string (pour migrer il faut ajouter 'N' en 32ème position + '' et NULL à la fin)
  • 2 colonnes ont été ajoutées dans mysql.db : Event_priv et Trigger_priv (pour migrer il faut ajouter 'Y' et 'Y' à la fin)

On pourra ainsi régler finement les droits d'un utilisateur en connaissant la signification de chaque colonne :

mysql> desc user;
+------------------------+-----------------------------------+------+-----+---------+-------+
| Field                  | Type                              | Null | Key | Default | Extra |
+------------------------+-----------------------------------+------+-----+---------+-------+
| Host                   | char(60)                          | NO   | PRI |         |       |
| User                   | char(16)                          | NO   | PRI |         |       |
| Password               | char(41)                          | NO   |     |         |       |
| Select_priv            | enum('N','Y')                     | NO   |     | N       |       |
| Insert_priv            | enum('N','Y')                     | NO   |     | N       |       |
| Update_priv            | enum('N','Y')                     | NO   |     | N       |       |
| Delete_priv            | enum('N','Y')                     | NO   |     | N       |       |
| Create_priv            | enum('N','Y')                     | NO   |     | N       |       |
| Drop_priv              | enum('N','Y')                     | NO   |     | N       |       |
| Reload_priv            | enum('N','Y')                     | NO   |     | N       |       |
| Shutdown_priv          | enum('N','Y')                     | NO   |     | N       |       |
| Process_priv           | enum('N','Y')                     | NO   |     | N       |       |
| File_priv              | enum('N','Y')                     | NO   |     | N       |       |
| Grant_priv             | enum('N','Y')                     | NO   |     | N       |       |
| References_priv        | enum('N','Y')                     | NO   |     | N       |       |
| Index_priv             | enum('N','Y')                     | NO   |     | N       |       |
| Alter_priv             | enum('N','Y')                     | NO   |     | N       |       |
| Show_db_priv           | enum('N','Y')                     | NO   |     | N       |       |
| Super_priv             | enum('N','Y')                     | NO   |     | N       |       |
| Create_tmp_table_priv  | enum('N','Y')                     | NO   |     | N       |       |
| Lock_tables_priv       | enum('N','Y')                     | NO   |     | N       |       |
| Execute_priv           | enum('N','Y')                     | NO   |     | N       |       |
| Repl_slave_priv        | enum('N','Y')                     | NO   |     | N       |       |
| Repl_client_priv       | enum('N','Y')                     | NO   |     | N       |       |
| Create_view_priv       | enum('N','Y')                     | NO   |     | N       |       |
| Show_view_priv         | enum('N','Y')                     | NO   |     | N       |       |
| Create_routine_priv    | enum('N','Y')                     | NO   |     | N       |       |
| Alter_routine_priv     | enum('N','Y')                     | NO   |     | N       |       |
| Create_user_priv       | enum('N','Y')                     | NO   |     | N       |       |
| Event_priv             | enum('N','Y')                     | NO   |     | N       |       |
| Trigger_priv           | enum('N','Y')                     | NO   |     | N       |       |
| Create_tablespace_priv | enum('N','Y')                     | NO   |     | N       |       |
| ssl_type               | enum('','ANY','X509','SPECIFIED') | NO   |     |         |       |
| ssl_cipher             | blob                              | NO   |     | NULL    |       |
| x509_issuer            | blob                              | NO   |     | NULL    |       |
| x509_subject           | blob                              | NO   |     | NULL    |       |
| max_questions          | int(11) unsigned                  | NO   |     | 0       |       |
| max_updates            | int(11) unsigned                  | NO   |     | 0       |       |
| max_connections        | int(11) unsigned                  | NO   |     | 0       |       |
| max_user_connections   | int(11) unsigned                  | NO   |     | 0       |       |
| plugin                 | char(64)                          | YES  |     |         |       |
| authentication_string  | text                              | YES  |     | NULL    |       |
+------------------------+-----------------------------------+------+-----+---------+-------+
42 rows in set (0.00 sec)

Par exemple, pour permettre à un utilisateur (ici debian-sys-maint) de faire des SHOW VIEW :

mysql> UPDATE user SET Show_view_priv='Y' WHERE User='debian-sys-maint';
mysql> FLUSH PRIVILEGES;

…que l'on peut aussi faire via :

mysql> GRANT SHOW VIEW on *.* to `debian-sys-maint`@localhost;

Pour créer un utilisateur sans droit particulier, par exemple pour du monitoring :

mysql> create user nrpe@localhost identified by 'PASSWORD';

On peut aussi gérer des droits sur les tables :

mysql> GRANT Select,Insert,Update ON foo.bar TO 'jdoe'@localhost;

Pour révoquer des droits sur une table, on utilisera REVOKE :

mysql> REVOKE ALL PRIVILEGES ON foo.bar FROM 'jdoe'@localhost;

/!\ Un droit est particulier : pour utiliser LOAD DATA INFILE ou SELECT INTO OUTFILE, il faut avoir le droit FILE … mais il est global (et dangereux) ! On le positionnera ainsi :

mysql> GRANT FILE ON *.* TO 'jdoe'@localhost;

Si l'on veux autoriser laccès a une base depuis un utilisateur MySQL, depuis lextérieur :

/!\ Il faut s'assurer que MySQL écoute bien sur toutes les IPs (bind-address = 0.0.0.0 dans la configuration MySQL)

Depuis une ip particulière :

mysql> GRANT ALL PRIVILEGES ON foo.* TO 'jdoe'@'IP_ADDRESS' IDENTIFIED BY 'PASSWORD';

Depuis toutes les IPs :

mysql> GRANT ALL PRIVILEGES ON foo.* TO 'jdoe'@'%' IDENTIFIED BY 'PASSWORD';

Si l'on ne connait pas le mot de passe, on peux utiliser le hash du mot de passe de l'utilisateur mysql comme ceci

mysql> GRANT ALL PRIVILEGES ON foo.* TO 'jdoe'@'%' IDENTIFIED BY PASSWORD '*E355A1AB8251C0B7E02ED8483696B2F3954C05CC';

Vérifications et réparations

Pour vérifier et réparer toutes les tables (une sorte de fsck pour les tables), on lancera :

# mysqlcheck --auto-repair --check --all-databases

On peut aussi réparer qu'une base en particulier :

# mysqlcheck --auto-repair --check foo

Note : ceci peut être à faire en cas d'arrêt inopiné du service.

Pour réparer une seule table :

mysql> CHECK TABLE foo.bar;
mysql> REPAIR TABLE foo.bar;

Dans le cas des tables MyISAM, si le REPAIR échoue, une réparation est aussi possible via myisamchk… à faire avec le service MySQL arrêté :

# myisamchk -r -q /var/lib/mysql/foo/bar.MYD

En cas d'échec (segfault par exemple), on peut tenter :

# myisamchk --safe-recover -v -f --key_buffer_size=512M --sort_buffer_size=512M --read_buffer_size=4M --write_buffer_size=4M /var/lib/mysql/BASE/TABLE.MYD

OPTIMIZE

Il est conseillé de lancer régulièrement la commande OPTIMIZE TABLE sur ses tables. Cela va réaliser une sorte de défragmentation des tables, notamment sur les indexes. C'est particulièrement recommandé sur les tables qui subissent beaucoup de changement, notamment des modifications/suppressions de lignes.

Voici comment on lance l'opération sur une table :

mysql> OPTIMIZE TABLE foo.bar;

On peut également lancer cela sur l'ensemble des tables d'une base (mais cela peut être très long) :

# mysqlcheck --optimize --all-databases

Note : lors d'un OPTIMIZE TABLE, la table est lockée.

Suivant le moteur utilisé pour une table, les opérations vont être différentes. Notamment pour le moteur InnoDB vous aurez un message du type Table does not support optimize, doing recreate + analyze instead et une table temporaire sera complètement recréée et remplacera l'ancienne (attention à l'espace disque !).

routines MySQL

mysql> select * from INFORMATION_SCHEMA.routines;

Changement mot de passe utilisateur

mysql> SET PASSWORD FOR 'jdoe'@'localhost' = PASSWORD('my_password');
MariaDB [(none)]> GRANT USAGE ON *.* TO 'jdoe'@'%' IDENTIFIED BY "passwd";

Par rapport à un autre utilisateur :

mysql> use mysql;
mysql> UPDATE mysql.user SET Password=PASSWORD('my_new_password') WHERE User='jdoe' and Host='localhost';

Changer variables globales d'environnement

On peut changer à chaud certaines variables globales d'environnement :

mysql> SET GLOBAL max_connect_errors=50;

ou

mysql> SET @@max_connect_errors=50;

Voici les changements utiles :

mysql> set global max_connections = 350;

Note : on prendra garde à modifier aussi en dur dans la configuration si le changement doit être persistent.

pt-query-digest

Un outil de Percona disponible dans le paquet percona-toolkit, pt-query-digest, permet de faire une analyse des slows query, il suffit de lui passer en paramètre le fichier de log des slows query :

# pt-query-digest /var/log/mysql/mysql-slow.log

ATTENTION : Si le fichier de slow query est trop lourd, il n'est pas recommandé de l'analyser sur un serveur de production, car l'analyse peut nécessiter un cœur CPU à 100%, pendant quelques minutes.

Cet outil analyse le fichier mysql-slow.log et fait un rapport général des requêtes qui prennent le plus de temps, par temps de réponse, pourcentage dexécution, nombres d'appels et le type de requête.

Exemple :

# Profile
# Rank Query ID           Response time  Calls R/Call  V/M   Item
# ==== ================== ============== ===== ======= ===== =============
#    1 0x67A347A2812914DF 830.5323 62.8%    41 20.2569 87.06 SELECT foo_bar
#    2 0xC5C7772FD65D8C64 141.2796 10.7%    35  4.0366  0.07 SELECT lignes commandes lignes
#    3 0x6DEF8BB001FA8845 139.9141 10.6%     7 19.9877  0.04 SELECT commandes commandes_remboursements vendeurs_factures_remises paiements livraisons commandes_statut commandes_groupes acheteurs codes_promos adresses pays adresses pays vendeurs adresses pays
#    4 0xC8A44AAD56105646  41.5405  3.1%    17  2.4436  0.02 SELECT produits_tendances vendeurs declinaisons texteproduits produits_tendances
#    5 0xFD38100E607E1331  26.7823  2.0%     2 13.3912  5.07 SELECT OUTFILE commandes_etiquettes
#    6 0xFD7F7A9702EE1C3C  21.4709  1.6%     6  3.5785  0.00 UPDATE commandes
#    7 0xE63D0402530F63BE   9.5435  0.7%     4  2.3859  0.00 UPDATE commandes
#    8 0x4EEE742BBDA4EE47   8.9621  0.7%     2  4.4810  0.02 SELECT OUTFILE vendeurtracking
#    9 0xB28EA31EC4438F2F   8.6173  0.7%     2  4.3087  0.02 SELECT OUTFILE lignes
#   10 0xFFAD96608E3F459B   6.7241  0.5%     2  3.3620  0.38 SELECT produits_tendances vendeurs declinaisons texteproduits produits_tendances

Puis il détaille, pour chaque requêtes, le temps dexécution, de lock, de colonnes envoyées et les colonnes examinées, les bases qui sont impacté par la requête, la taille de la requête et la requête complète.

Une astuce pour analyser les requêtes de tout le serveur MySQL et pas seulement les slow query, serait de mettre la valeur long_query_time=0 pendant quelques heures et de d'analyser le fichier de log avec pt-query-digest.

Attention cependant, avec long_query_time=0 la taille du fichier de logs peux grossir très vite, il faut donc surveiller l'espace disque.

Lister les variables de configuration

Pour voir la liste de toutes les variables :

mysql> show variables;

Pour ne voir qu'un sous-ensemble de variables :

mysql> show variables like 'read_only';
mysql> show variables like '%thread%';

Lecture seule

Si on veut qu'une instance de MySQL soit démarrée en lecture seule, on peut ajouter la variable read_only = 1 dans la section [mysqld]. Seules les requêtes faites par des utilisateurs ayant le privilège SUPER seront alors exécutées.

C'est par exemple utile dans une situation où une instance "slave" doit pouvoir être utilisée en lecture seule, tout en utilisant les mêmes comptes utilisateurs qui ont accès en écriture sur le "master". La réplication en elle-même n'est pas impactée.

Logs

Log de toutes les requêtes

On peut activer à chaud le logging de l'ensemble des requêtes :

mysql> SET GLOBAL GENERAL_LOG=ON;

Toutes les requêtes seront immédiatemment écrites dans le fichier DATADIR/HOSTNAME.log.

Pour désactiver à chaud :

mysql> SET GLOBAL GENERAL_LOG=OFF;

Note : évidemment, sur un serveur de production il faut éviter d'activer cela plus de quelques secondes car cela impacte fortement la performance et cela va rapidement remplir l'espace disque.

Log des requêtes lentes (slow queries)

Pour débugger les applications lentes, c'est une fonctionnalité intéressante de trouver quelle requête est longue. Pour cela on peut spécifier quand une requête est considérée comme longue, le chemin où stocker les requêtes, et l'activation des logs.

[mysqld]
long_query_time = 5
slow_query_log = 1
slow_query_log_file = /var/log/mysql/slow.log

Ou à chaud :

mysql> SET GLOBAL slow_query_log=ON;
mysql> SET GLOBAL long_query_time=5;
mysql> SET GLOBAL slow_query_log_file= "/var/log/mysql/slow.log";

Il est également possible de remonter les requêtes n'utilisant pas d'index (qu'importe le temps qu'elle prennent pour s'exécuter), avec le paramètre booléen log_queries_not_using_indexes.

Pour avoir une meilleure lecture des slow query, on peut utilisé la commande mysqldumpslow :

# mysqldumpslow /var/log/mysql/mysql-slow.log

Log des dead lock

Note : Seulement possible depuis MySQL 5.6 ou MariaDB 10.

[mysqld]
innodb_print_all_deadlocks = on

À chaud :

mysql> SET GLOBAL innodb_print_all_deadlocks=on;

Sauvegarde

Pour sauvegarder une base de données dans un seul fichier (sans et avec compression) :

$ mysqldump --hex-blob foo > foo.sql
$ mysqldump --hex-blob foo | gzip > foo.sql.gz

Note : l'option --hex-blob est importante pour ne pas risquer de perdre certains caractères dans les colonnes de type BINARY/BLOB/BIT

Il est aussi possible de sauvegarder une seule table avec mysqldump. Exemple avec la table bar de la base foo : $ mysqldump --hex-blob foo bar

Pour sauvegarder une base de données au format tab-separated data files, avec - pour chaque table - un fichier .sql contenant la structure de la table (CREATE TABLE) et un fichier .txt contenant les données brutes (ré-injectable avec LOAD DATA INFILE) :

# mkdir /tmp/foo && chown mysql:mysql /tmp/foo
$ mysqldump -T foo > /tmp/foo

Note : le répertoire de destination doit exister et mysqld doit avoir les droits d'écrire dedans.

On peut utiliser les options --fields-xxx pour obtenir des fichiers au format CSV :

$ mysqldump --hex-blob --fields-enclosed-by='\"' --fields-terminated-by=',' -T /tmp/foo foo

Pour sauvegarder toutes les bases (exemples en mode classique et en mode -T) :

$ mysqldump --opt --all-databases --events --hex-blob > all.sql
$ for db in $(mysql -P3308 -e "SHOW DATABASES" | egrep -v "^(Database|information_schema|performance_schema)") \
  mkdir /backupmysql/$db && chown mysql:mysql /backupmysql/$db && \
  mysqldump --events --hex-blob -T /backupmysql/$db $db; done

Pour sauvegarder uniquement certaines tables :

$ mysqldump --hex-blob foo TABLE0 [TABLE1…] > foo_tables.sql

Pour presque faire un --exclude (qui manque cruellement à mysqldump):

$ mysql -B -N -e 'show databases' | \
   perl -ne 'print unless /\b(?:phpmyadmin|mysql|information_schema)\b/' | \
   xargs echo mysqldump --hex-blob -B

Et pour sauvegarder des tables correspondant à un motif (préfixe le plus souvent) :

$ mysqldump --hex-blob foo $(mysql foo -B --column-names=False -e "show tables like 'exemple_%'") > foo_motif.sql

Pour exclure les VIEWS d'un mysqldump :

EXCLUDE_VIEWS=$(echo "SELECT TABLE_SCHEMA, TABLE_NAME from INFORMATION_SCHEMA.VIEWS" | mysql information_schema | sed '/^TABLE_SCHEMA/d' | gawk {'print $1"." $2'} |tr '\n' ',')

mysqldump  --opt --all-databases --force --ignore-table=$EXCLUDE_VIEWS --events --hex-blob > foo.sql

Pour dumper avec une condition particulière :

$ mysqldump -t foo bar --hex-blob --where="id='66666666'"

Ce qui permet de réinjecter des données résultantes d'un SELECT * FROM foo.bar WHERE id='66666666'.

Il est évidement possible de faire toutes ces opérations sur une instance en précisant son port avec l'option --port (valable pour mysqldump et mysql).

Pour obtenir une liste des utilisateurs mysql, on peut utiliser cette fonction (glanée sur serverfault) :

mygrants()
{
  mysql -B -N -e "SELECT DISTINCT CONCAT(
    'SHOW GRANTS FOR *, user, _'@'_, host, *;'
    ) AS query FROM mysql.user" | \
  mysql | \
  sed 's/\(GRANT .*\)/\1;/;s/^\(Grants for .*\)/## \1 ##/;/##/{x;p;x;}'
}

Pour avoir un dump avec un seul insert par ligne, pratique pour restaurer partiellement les bases mysql.user et mysql.db par exemple :

$ mysqldump --skip-extended-insert --events --hex-blob mysql > mysql.sql

Pour sauvegarder une grosse base de donnée en innodb (et uniquement avec ce moteur!), on peut ajouter l'argument --single-transaction qui permet d'effectuer le dump dans une transaction et ainsi ne pas verrouiller les tables.

Restauration

Pour restaurer une base de données (sans et avec compression) :

$ mysqladmin create foo
$ mysql -o foo < foo.sql
$ gunzip < foo.sql.gz | mysql foo

Pour restaurer uniquement la base foo :

$ mysql -o foo < all.sql

Mais si venant d'un dump complet voir aussi : Restaurer une base depuis un dump complet

Pour restaurer une table de type "tab-separated data files" (mysqldump -T) dans une base foo (exemples par défaut et avec des options --fields-xxx) :

$ mysqlimport --default-character-set=utf8 foo /tmp/foo/bar.txt
$ mysqlimport --default-character-set=utf8 --fields-enclosed-by='\"' --fields-terminated-by=',' foo /tmp/foo/bar.txt

Pour restaurer une base entière avec un dump de type "tab-separated data files" (exemples par défaut et avec des options --fields-xxx) :

db=test1

for file in *.sql; do
   mysql $db <$file
done

grep CHARSET= *txt

for file in *.txt; do
   tablename=$(basename $file .txt)
   echo "LOAD DATA INFILE '$PWD/$file' INTO TABLE \`$tablename\`" CHARACTER SET utf8 | mysql $db
   #echo "LOAD DATA INFILE '$PWD/$file' INTO TABLE \`$tablename\`" CHARACTER SET utf8 FIELDS TERMINATED BY ',' ENCLOSED BY '"' | mysql $db
done

Note 1 : Attention, l'utilisateur MySQL doit avoir le droit de lecture sur les fichiers .txt Se positionner dans un répertoire où mysql a les droits (mysqltmp - /home/mysqltmp par ex).

Note 2 : Si vous n'avez pas toutes vos tables en utf8 (par exemple du CHARSET=LATIN1), ce n'est pas bien… et vous devrez pour la peine adapter le script (en détectant le charset utilisé avec « file » si nécessaire)

Note 3 : Si erreur 150 : «Can't create table» voir du côté des foreign keys :

$ mysql -e 'SHOW ENGINE INNODB STATUS\G;' | grep LATEST\ FOREIGN -A3

et ignorer les erreurs pour pouvoir recréer les tables :

$ mysql -e "set GLOBAL foreign_key_checks=OFF;"

Si cela concerne plusieurs bases réparties dans différents sous-répertoires :

cd /home/mysqldump
for dir in *
do
  echo "=======base $dir========="
  db=$dir
  mysql -e "create database ${dir};"
  ls $dir/*.sql || continue
  for file in $dir/*.sql
  do
    mysql $db <$file
  done
  grep CHARSET= $dir/*txt
  ls $dir/*.txt || continue
  for file in $dir/*.txt
  do
    tablename=$(basename $file .txt)
    echo "LOAD DATA INFILE '$PWD/$file' INTO TABLE $tablename" CHARACTER SET utf8 | mysql $db
  done
done

On peut également restaurer un dump foo.sql (ou tout script au format SQL) de façon interactive via la commande source :

mysql> source foo.sql

Note 1 : il est nécessaire que MySQL ait les droits de lecture sur le fichier foo.sql

Note 2 : les sorties des requêtes sont renvoyées sur la sortie standard (au contraire de la restauration avec mysql < foo.sql)

Pour extraire une table précise d'un dump complet (en vue de la restaurer ensuite) :

$ awk '/^-- Table structure for table `<matable>`/,/^UNLOCK TABLES;/{print}' mabase.sql >matable.sql

Monitoring

Pour surveiller un service MySQL en production, on pourra faire :

# mysqladmin status
# mysqladmin extended-status
# mysqladmin processlist

mytop

Pour avoir une version conviviale et dynamique des process en cours, on utilisera l'outil mytop.

# apt install mariadb-client-10.1 libconfig-inifiles-perl libterm-readkey-perl

Note : Pour Debian 7 et 8, c'était dans un package indépendant :

# aptitude install mytop

On édite le fichier /root/.mytop ainsi :

user = debian-sys-maint
pass = PASSWORD
db = mysql

Reste plus qu'à lancer la commande mytop -s1 (pour un rafraichissement toutes les secondes) : on appréciera les raccourcis p (mettre en pause l'affichage), o (pour voir en 1er les requêtes les plus longues), k (pour killer une requête… par exemple celle qui bloque toutes les autres) et ? (pour voir les autres raccourcis possibles).

L'outil mytop se sert principalement de la requête SHOW PROCESSLIST que l'on pourra bien sûr lancer manuellement. Tout comme KILL :

mysql> SHOW PROCESSLIST;
mysql> KILL <id_requête>;

Pour lister les requêtes qui durent plus de 30 secondes pour pouvoir les tuer facilement :

# mysql -e 'select group_concat(concat("kill ",ID) separator ";") from information_schema.processlist where TIME>=30;'

Puis exécuter le résultat avec la commande mysql, exemple :

# mysql -e 'kill 1854;kill 1853;kill 1852;kill 1851;kill 1850;kill 1848'

Pour surveiller le moteur InnoDB, on utilisera la commande suivante :

mysql> SHOW ENGINE INNODB STATUS;

Installation de mytop sur Debian9 avec MySQL 5.7 (Oracle)

Sur debian9 mytop fait partie du paquet mariadb-client, et n'est plus disponible en stand alone, cela pose un problème si on installe MySQL depuis les dépôts d'oracle.

Il faut prendre le paquet mytop de jessie et l'installer sur stretch :

# wget http://ftp.de.debian.org/debian/pool/main/m/mytop/mytop_1.9.1-2_all.deb
# dpkg -i mytop_1.9.1-2_all.deb

Il se peut qu'il y est des dépendances manquante dans ce cas il faut les installer :

# apt install libdbi-perl libdbd-mysql-perl libconfig-inifiles-perl
# apt --fix-broken install

Munin

Pour activer les plugins MySQL pour Munin :

# cd /etc/munin/plugins
# ln -s /usr/share/munin/plugins/mysql_bytes
# ln -s /usr/share/munin/plugins/mysql_queries
# ln -s /usr/share/munin/plugins/mysql_slowqueries
# ln -s /usr/share/munin/plugins/mysql_threads

On pourra aussi activer le plugin mysql_ avec des liens symboliques nommés connections, files_tables, innodb_bpool, innodb_bpool_act, innodb_io, innodb_log, innodb_rows, innodb_semaphores, myisam_indexes, qcache, qcache_mem, sorts ou tmp_tables.

Pour tester le bon fonctionnement des plugins MySQL pour Munin :

# munin-run mysql_bytes

log2mail

Afin d'être alerté en cas de souci, il est conseillé d'ajouter la configuration suivante au logiciel log2mail :

file = /var/log/syslog
pattern = "is marked as crashed and should be repaired"
mailto = monitoring@example.com
template = /etc/log2mail/template.mysql

file = /var/log/syslog
pattern = "init function returned error"
mailto = monitoring@example.com
template = /etc/log2mail/template.mysql

file = /var/log/syslog
pattern = "try to repair it"
mailto = monitoring@example.com
template = /etc/log2mail/template.mysql

file = /var/log/syslog
pattern = "InnoDB: Fatal error"
mailto = monitoring@example.com
template = /etc/log2mail/template.mysql

file = /var/log/syslog
pattern = "as a STORAGE ENGINE failed"
mailto = monitoring@example.com
template = /etc/log2mail/template.mysql

Le fichier /etc/log2mail/template.mysql contenant :

From: %f
To: %t
Subject: MySQL problem

Hello!

We have matched your pattern "%m" in "%F" %n times:

%l

Yours,
log2mail.

Note : il faut ajouter l'utilisateur log2mail dans le groupe adm.

binlogs

Par défaut, MySQL stocke chaque requête en écriture dans des fichiers appelés binlogs.

Configuration

Par défaut les binlogs sont conservés sur 10 jours, avec des fichiers n'excédant pas 100 Mo :

[mysqld]
log_bin          = /var/log/mysql/mysql-bin.log
expire_logs_days  = 10
max_binlog_size   = 100M
#binlog_do_db     = include_database_name
#binlog_ignore_db = include_database_name
binlog_format     = mixed

Note : depuis Debian 9, il faut explicitement préciser la directive log_bin pour activer les binlogs.

Format

http://dev.mysql.com/doc/refman/5.5/en/binary-log-setting.html

On peut choisir 3 types de format pour les binlogs :

  • statement : les requêtes INSERT / UPDATE sont conservées
  • row : les modifications de chaque ligne sont conservées (via une sorte de code « binaire » propre à MySQL)
  • mixed : en mode statement… sauf dans certains cas où cela passe en mode row

Avantages et inconvénients :

Le mode statement est utile pour conserver en clair toutes les requêtes. Il permet aussi de meilleures performances quand des UPDATE contiennent des clauses WHERE qui modifient de nombreuses lignes. Pour de la réplication, il peut être non fiable car le résultat d'un UPDATE peut donner des résultats différents sur un serveur SLAVE. Cela peut aussi poser des soucis avec les transactions InnoDB.

Le mode row a l'inconvénient de rendre illisibles toutes les requêtes. Dans certains cas particuliers (UPDATE contiennent des clauses WHERE qui modifient de nombreuses lignes), il peut être moins performant. Il a l'avantage d'être plus fiable pour de la réplication.

Le mode mixed est un bon compromis pour de la réplication : il permet de voir la plupart des requêtes en clair, mais évite le problème de fiabilité en passant en mode row quand c'est nécessaire.

Informations

On peut savoir le dernier binlog écrit :

mysql> show master status;
+------------------+----------+--------------+------------------+
| File             | Position | Binlog_Do_DB | Binlog_Ignore_DB |
+------------------+----------+--------------+------------------+
| mysql-bin.020505 | 17736280 |              |                  |
+------------------+----------+--------------+------------------+
1 row in set (0.00 sec)

On peut lister l'ensemble des binlogs vus par MySQL :

mysql> show binary logs;
+------------------+-----------+
| Log_name         | File_size |
+------------------+-----------+
| mysql-bin.020437 |  18697341 |
| mysql-bin.020438 | 104858013 |
| mysql-bin.020439 | 104858274 |
| mysql-bin.020440 | 104863158 |
[…]

Et les visualiser d'un point de vue filesystem :

# ls -l /var/log/mysql/

-rw-rw---- 1 mysql adm  18697341 Nov 29 00:01 mysql-bin.020437
-rw-rw---- 1 mysql adm 104858013 Nov 29 09:41 mysql-bin.020438
-rw-rw---- 1 mysql adm 104858274 Nov 29 13:10 mysql-bin.020439
-rw-rw---- 1 mysql adm 104863158 Nov 29 17:28 mysql-bin.020440
[…]
-rw-rw---- 1 mysql adm  17863542 Dec  9 01:24 mysql-bin.020505
-rw-rw---- 1 mysql adm      2208 Dec  9 00:01 mysql-bin.index

Suppression

Il faut vérifier sur le slave quel est le dernier binlog qu'il a récupéré/traité. Pour cela on fait SHOW SLAVE STATUS\G, puis on note la ligne Relay_Master_Log_File:. Elle indique le dernier binlog récupéré/traité. On peut donc supprimer sur le master, tout ceux d'avant. Par précaution, on peut en garder 10.

Exemple : Relay_Master_Log_File: mysql-bin.009628 → sur le master BINARY LOGS TO 'mysql-bin.009618';

Pour supprimer les binlogs antérieurs à mysql-bin.00NNNN :

mysql> PURGE BINARY LOGS TO 'mysql-bin.00NNNN';

ou par rapport à une date :

mysql> PURGE BINARY LOGS BEFORE "2011-12-07 00:00:00";

Si cela vient à se reproduire régulièrement, on peut baisser le nombre de jour durant lesquels les binlogs sont gardés avec la directive expire_logs_days.

On peut automatiser la tâche avec l'outil mysqlbinlogpurge.

Exemple :

mysqlbinlogpurge --master=login:password@192.0.2.1:3306 --slaves=login:password@192.0.2.2:3306

Note : Il est nécessaire que le slave s'annonce avec --report-host et --report-port.

Désactivation

Pour désactiver les binlogs, on ajoutera l'option suivante dans la configuration :

[mysqld]
disable-log-bin

Lecture

On pourra lire en ligne de commande le contenu d'un binlog via la commande :

# mysqlbinlog /var/log/mysql/mysql-bin.001789 | less
  • Note* : si vous obtenez une erreur mysqlbinlog: unknown variable 'default-character-set=utf8' c'est que la directive default-character-set a été placée dans la configuration MySQL (/etc/mysql ou .my.cnf) dans la mauvaise section : [client] au lieu de [mysql] (ou [mysqldump]). On peut aussi lancer la commande avec l'option --no-defaults.

Replay

/!\ **ATTENTION, CES MANIPULATIONS PEUVENT ÊTRE DANGEREUSES VOS DONNÉES, BIEN SAVOIR CE QUE L'ON FAIT ! **

On pourra ainsi injecter le contenu d'un binlog dans une base… tout simplement avec une commande du type :

# mysqlbinlog /var/log/mysql/mysql-bin.001789 | mysql -P3307

À noter que si une partie des données étaient déjà présentes (cas d'un binlog corrompu lors d'incident lors d'une réplication), on pourra procéder ainsi :

# mysqlbinlog /var/log/mysql/mysql-bin.001789 > mysql-bin.001789.txt
# sed -i 's/INSERT INTO/INSERT IGNORE INTO/gi' mysql-bin.001789.txt
# cat mysql-bin.001789.txt | mysql -P3307

On peut aussi injecter les binlogs, sur une intervale de date et heure précise, en précisant le début et la fin comme ceci :

# mysqlbinlog --database foo --start-datetime='2018-12-27 16:44:57' --stop-datetime='2018-12-27 16:58:00' binlog.*|mysql -u user -p password

SET sql_log_bin = 0

On peut effectuer des requêtes SQL qui ne seront pas écrites dans le binlog. Pour cela on positionne la variable sql_log_bin à 0 et les requêtes interactives suivantes ne seront pas prises en compte dans le binlog (bien sûr, si l'on quitte le CLI MySQL, cela ne sera plus valable) :

mysql> SET sql_log_bin = 0;

Note : cela nécessite le droit MySQL SUPER

Multiples instances MySQL

Il est possible de faire fonctionner plusieurs instances de MySQL sur un serveur ; chacune avec ses propres données et sa propre configuration.

Installation

Avant toute opération, il est nécessaire de commenter cette ligne dans le /etc/mysql/my.cnf :

#user = mysql

Et de rajouter ces lignes dans /etc/mysql/conf.d/50-multi.cnf :

[mysqld_multi]
user = mysqladmin

Créer un utilisateur pour l'instance (il doit avoir un shell valide comme /bin/sh) :

# useradd mysqld1

Créer le dossier qui va accueillir le datadir et donner les bons droits :

# mkdir -p /srv/mysqld_instances/mysqld1 /var/log/mysql/mysqld1
# chmod 755 /srv /srv/mysqld_instances
# chown -R mysqld1:mysqld1 /srv/mysqld_instances/mysqld1 /var/log/mysql/mysqld1

Créer un repertoire temporaire dédié à cette instance :

# mkdir /home/mysqld1-tmp
# chown mysqld1:mysqld1 /home/mysqld1-tmp

Créer ensuite le datadir :

# mysql_install_db --user=mysqld1 --datadir=/srv/mysqld_instances/mysqld1
# chmod 700 /srv/mysqld_instances/mysqld1

Ajouter ces lignes dans /etc/mysql/conf.d/zzz_mysqld1.cnf :

[mysqld1]
mysqld = /usr/bin/mysqld_safe
user = mysqld1
port = 3307
tmpdir = /home/mysqld1-tmp/
socket = /var/run/mysqld_instances/mysqld1/mysqld.sock
pid-file = /var/run/mysqld_instances/mysqld1/mysqld.pid
datadir = /srv/mysqld_instances/mysqld1
log_error = /var/log/mysql/mysqld1/error.log
slow_query_log_file = /var/log/mysql/mysqld1/mysql-slow.log

Note 1 : même si l'on ne prévoit pas de faire tourner le mysqld principal sur le port 3306, on préfère tout de même utiliser le port 3307 pour la première instance afin de ne pas confondre une configuration avec et sans instance.

Note 2 : dans le cas où une réplication est déjà active sur l'instance principale, la nouvelle instance créée va automatiquement hériter des paramètres de réplication. Pour éviter ça, il suffit de rajouter :

[mysqld1]
skip-slave-start

Si /usr est monté en RO, déplacer le log de mysqld_multi :

# mv /usr/share/mysql/mysqld_multi.log /var/log/mysql/mysqld_multi.log
# ln -s /var/log/mysql/mysqld_multi.log /usr/share/mysql/mysqld_multi.log
# chown mysql:adm /var/log/mysql/mysqld_multi.log

Puis lancer la nouvelle instance :

# mysqld_multi start 1

Enfin, n'oubliez pas de définir un mot de passe root/mysqladmin pour la nouvelle instance !

Pour voir l'état des instances :

# mysqld_multi report

Et pour stopper une instance, on évite la commande « mysqld_multi stop 1 » qui n'est que rarement fiable et peut laisser l'instance dans un état incorrect, difficile à récupérer.

On préfère passer la commande « shutdown » en interne :

# mysqladmin -h 127.0.0.1 -P3307 shutdown

Note : a priori cela revient à envoyer un signal SIGTERM (kill -15) au process mysqld

Nettoyage

Si le mysqld principal n'est pas utilisé, on désactivera le script d'init.d /etc/init.d/mysql (en ajoutant exit 0 au début du script) et on pourra se créer un script /etc/init.d/mysqld_instances du type :

#!/bin/sh
#
### BEGIN INIT INFO
# Provides:          mysqld_instances
# Required-Start:    $remote_fs $syslog
# Required-Stop:     $remote_fs $syslog
# Should-Start:      $network $time
# Should-Stop:       $network $time
# Default-Start:     2 3 4 5
# Default-Stop:      0 1 6
# Short-Description: Start and stop the mysql database server daemon
# Description:       Controls the main MySQL database server daemon "mysqld"
#                    and its wrapper script "mysqld_safe".
### END INIT INFO
#
set -e
set -u

mkdir -p /run/mysqld_instances && chown root:mysql /run/mysqld_instances && chmod 770 /run/mysqld_instances

case "$1" in
        start)
                mysqld_multi start
                ;;
        stop)
                for pid in /run/mysqld_instances/*/mysqld.pid; do
                    pkill -F "${pid}"
                done
                ;;
        status)
                mysqld_multi report
                ;;
        restart)
                $0 stop
                $0 start
                ;;
  *)
        echo "Usage: $0 {start|stop|status|restart}"
        exit 1
esac

exit 0

Administration

Pour voir le statut de l'instance n°1, logiquement nommée mysqld1 (GNR=1) et tournant sur le port 3307 :

# mysqld_multi report 1
Reporting MySQL servers
MySQL server from group: mysqld1 is running

Pour l'arrêter/redémarrer, même principe (attention, mysqld_multi est peu verbeux) :

# ps auwx | grep 3307
# mysqladmin -P 3307 shutdown
# ps auwx | grep 3307
# mysqld_multi start 1
# ps auwx | grep 3307

Optimisation avancée

Voir /HowtoMySQL/Optimize.

Réplication MySQL

Voir /HowtoMySQL/Replication.

FAQ et erreurs courantes

Voir /HowtoMySQL/Troubleshooting.