Les bases de données open source deviennent rapidement courantes, de sorte que la migration des moteurs propriétaires vers les moteurs open source est une sorte de tendance de l'industrie maintenant. Cela signifie également que nous, les DBA, finissons souvent par avoir plusieurs bases de données à gérer.
Dans les derniers articles de blog, mon collègue Paul Namuag et moi avons couvert plusieurs aspects de la migration d'Oracle vers Percona, MariaDB et MySQL. L'objectif évident de la migration est de rendre votre application opérationnelle plus efficacement dans le nouvel environnement de base de données, mais il est essentiel de s'assurer que le personnel est prêt à la prendre en charge.
Ce blog couvre les opérations de base de MySQL en référence à des tâches similaires que vous effectueriez quotidiennement dans votre environnement Oracle. Il vous fournit une plongée approfondie sur différents sujets pour vous faire gagner du temps, car vous pouvez vous rapporter aux connaissances Oracle que vous avez déjà acquises au fil des ans.
Nous parlerons également des outils de ligne de commande externes qui manquent dans l'installation par défaut de MySQL mais qui sont nécessaires pour effectuer efficacement les opérations quotidiennes. La version open source n'est pas fournie avec l'équivalent d'Oracle Cloud Control par exemple, alors consultez ClusterControl si vous recherchez quelque chose de similaire.
Dans ce blog, nous supposons que vous avez une meilleure connaissance d'Oracle que de MySQL et que vous aimeriez donc connaître la corrélation entre les deux. Les exemples sont basés sur la plate-forme Linux, mais vous pouvez trouver de nombreuses similitudes dans la gestion de MySQL sous Windows.
Comment puis-je me connecter à MySQL ?
Commençons notre voyage avec une tâche très (apparemment) basique. En fait, il s'agit d'un type de tâche qui peut entraîner une certaine confusion en raison des différents concepts de connexion dans Oracle et MySQL.
L'équivalent de la connexion sqlplus / as sysdba est la commande de terminal "mysql" avec un drapeau -uroot. Dans le monde MySQL, le superutilisateur est appelé root. Les utilisateurs de la base de données MySQL (y compris root) sont définis par le nom et l'hôte à partir desquels ils peuvent se connecter.
Les informations sur l'utilisateur et les hôtes à partir desquels il peut se connecter sont stockées dans la table mysql.user. Lors de la tentative de connexion, MySQL vérifie si l'hôte client, le nom d'utilisateur et le mot de passe correspondent à la ligne de la table de métadonnées.
C'est une approche un peu différente de celle d'Oracle où nous n'avons qu'un nom d'utilisateur et un mot de passe, mais ceux qui connaissent Oracle Connection Manager pourraient trouver des similitudes.
Vous ne trouverez pas d'entrées TNS prédéfinies comme dans Oracle. Habituellement, pour une connexion administrateur, nous avons besoin de l'utilisateur, du mot de passe et de l'indicateur d'hôte -h. Le port par défaut est 3306 (comme 1521 dans Oracle) mais cela peut varier selon les différentes configurations.
Par défaut, de nombreuses installations auront une connexion d'accès root à partir de n'importe quelle machine ([email protected]'%') bloquée, vous devez donc vous connecter au serveur hébergeant MySQL, généralement via ssh.
Tapez ce qui suit :
mysql -u root
Lorsque le mot de passe root n'est pas défini, cela suffit. Si le mot de passe est requis, vous devez ajouter le drapeau -p.
mysql -u root -p
Vous êtes maintenant connecté au client mysql (l'équivalent de sqlplus) et vous verrez une invite, généralement 'mysql>'.
MySQL est-il opérationnel ?
Vous pouvez utiliser le script de démarrage du service mysql ou la commande mysqladmin pour savoir s'il est en cours d'exécution. Ensuite, vous pouvez utiliser la commande ps pour voir si les processus mysql sont opérationnels. Une autre alternative peut être mysqladmin, qui est un utilitaire utilisé pour effectuer des opérations administratives.
mysqladmin -u root -p status
Sur Debian :
/etc/init.d/mysql status
Si vous utilisez RedHat ou Fedora, vous pouvez utiliser le script suivant :
service mysqld status
Ou
/etc/init.d/mysqld status
Ou
systemctl status mysql.service
Sur les instances MariaDB, vous devez rechercher le nom du service MariaDB.
systemctl status mariadb
Que contient cette base de données ?
Comme dans Oracle, vous pouvez interroger les objets de métadonnées pour obtenir des informations sur les objets de base de données.
Il est courant d'utiliser ici des raccourcis, des commandes qui vous aident à répertorier les objets ou à obtenir le DDL des objets.
show databases;
use database_name;
show tables;
show table status;
show index from table_name;
show create table table_name;
Semblable à Oracle, vous pouvez décrire la table :
desc table_name;
Où mes données sont-elles stockées ?
Il n'y a pas de stockage interne dédié comme ASM dans MySQL. Tous les fichiers de données sont placés dans les points de montage standard du système d'exploitation. Avec une installation par défaut, vous pouvez retrouver vos données dans :
/var/lib/mysql
L'emplacement est basé sur la variable datadir.
[email protected]:~# cat /etc/mysql/my.cnf | grep datadir
datadir=/var/lib/mysql
Vous y verrez un répertoire pour chaque base de données.
Selon la version et le moteur de stockage (oui il y en a quelques-uns ici), le répertoire de la base de données peut contenir des fichiers au format *.frm, qui définissent la structure de chaque table de la base de données. Pour les tables MyISAM, les données (*.MYD) et les index (*.MYI) sont également stockés dans ce répertoire.
Les tables InnoDB sont stockées dans des espaces de table InnoDB. Chacun d'entre eux se compose d'un ou plusieurs fichiers, qui sont similaires aux tablespaces Oracle. Dans une installation par défaut, toutes les données et tous les index InnoDB pour toutes les bases de données sur un serveur MySQL sont conservés dans un seul tablespace, composé d'un seul fichier :/var/lib/mysql/ibdata1. Dans la plupart des configurations, vous ne gérez pas les espaces de table comme dans Oracle. La meilleure pratique consiste à les conserver avec l'extension automatique activée et la taille maximale illimitée.
[email protected]:~# cat /etc/mysql/my.cnf | grep innodb-data-file-path
innodb-data-file-path = ibdata1:100M:autoextend
InnoDB possède des fichiers journaux, qui sont l'équivalent des redo logs d'Oracle, permettant une récupération automatique après un crash. Par défaut, il existe deux fichiers journaux :/var/lib/mysql/ib_logfile0 et /var/lib/mysql/ib_logfile1. Les données d'annulation sont conservées dans le fichier d'espace de table.
[email protected]:/var/lib/mysql# ls -rtla | grep logfile
-rw-rw---- 1 mysql mysql 268435456 Dec 15 00:59 ib_logfile1
-rw-rw---- 1 mysql mysql 268435456 Mar 6 11:45 ib_logfile0
Où se trouvent les informations de métadonnées ?
Il n'y a pas de vues de type dba_*, user_*, all_* mais MySQL a des vues de métadonnées internes.
Information_schema est défini dans la norme SQL 2003 et est implémenté par d'autres bases de données majeures, par ex. SQL Server, PostgreSQL.
Depuis MySQL 5.0, la base de données information_schema est disponible, contenant les informations du dictionnaire de données. Les informations étaient en fait stockées dans les fichiers FRM externes. Enfin, après de nombreuses années, les fichiers .frm ont disparu dans la version 8.0. Les métadonnées sont toujours visibles dans la base de données information_schema mais utilisent le moteur de stockage InnoDB.
Pour voir toutes les vues réelles contenues dans le dictionnaire de données du client mysql, passez à la base de données information_schema :
use information_schema;
show tables;
Vous pouvez trouver des informations supplémentaires dans la base de données MySQL, qui contient des informations sur la base de données, les événements (tâches MySQL), les plugins, la réplication, la base de données, les utilisateurs, etc.
Le nombre de vues dépend de la version et du fournisseur.
Sélectionnez * à partir de v$session
Le select * from v$session d'Oracle est représenté ici avec la commande SHOW PROCESSLIST qui affiche la liste des threads.
mysql> SHOW PROCESSLIST;
+---------+------------------+------------------+--------------------+---------+--------+--------------------+------------------+-----------+---------------+
| Id | User | Host | db | Command | Time | State | Info | Rows_sent | Rows_examined |
+---------+------------------+------------------+--------------------+---------+--------+--------------------+------------------+-----------+---------------+
| 1 | system user | | NULL | Sleep | 469264 | wsrep aborter idle | NULL | 0 | 0 |
| 2 | system user | | NULL | Sleep | 469264 | NULL | NULL | 0 | 0 |
| 3 | system user | | NULL | Sleep | 469257 | NULL | NULL | 0 | 0 |
| 4 | system user | | NULL | Sleep | 469257 | NULL | NULL | 0 | 0 |
| 6 | system user | | NULL | Sleep | 469257 | NULL | NULL | 0 | 0 |
| 16 | maxscale | 10.0.3.168:5914 | NULL | Sleep | 5 | | NULL | 4 | 4 |
| 59 | proxysql-monitor | 10.0.3.168:6650 | NULL | Sleep | 7 | | NULL | 0 | 0 |
| 81 | proxysql-monitor | 10.0.3.78:62896 | NULL | Sleep | 6 | | NULL | 0 | 0 |
| 1564 | proxysql-monitor | 10.0.3.78:25064 | NULL | Sleep | 3 | | NULL | 0 | 0 |
| 1822418 | cmon | 10.0.3.168:41202 | information_schema | Sleep | 0 | | NULL | 0 | 8 |
| 1822631 | cmon | 10.0.3.168:43254 | information_schema | Sleep | 4 | | NULL | 1 | 1 |
| 1822646 | cmon | 10.0.3.168:43408 | information_schema | Sleep | 0 | | NULL | 464 | 464 |
| 2773260 | backupuser | localhost | mysql | Query | 0 | init | SHOW PROCESSLIST | 0 | 0 |
+---------+------------------+------------------+--------------------+---------+--------+--------------------+------------------+-----------+---------------+
13 rows in set (0.00 sec)
Il est basé sur les informations stockées dans la vue information_schema.processlist. La vue nécessite d'avoir le privilège PROCESS. Cela peut également vous aider à vérifier si vous n'avez pas atteint le nombre maximum de processus.
Où se trouve un journal des alertes ?
Le journal des erreurs peut être trouvé dans my.cnf ou via la commande show variables.
mysql> show variables like 'log_error';
+---------------+--------------------------+
| Variable_name | Value |
+---------------+--------------------------+
| log_error | /var/lib/mysql/error.log |
+---------------+--------------------------+
1 row in set (0.00 sec)
Où se trouve la liste des utilisateurs et leurs autorisations ?
Les informations sur les utilisateurs sont stockées dans la table mysql.user, tandis que les autorisations sont stockées à plusieurs endroits, notamment mysql.user, mysql.tables_priv,
L'accès utilisateur MySQL est défini dans :
mysql.columns_priv, mysql.tables_priv, mysql.db,mysql.user
La meilleure façon de répertorier les subventions est d'utiliser pt-grants, l'outil de la boîte à outils Percona (un incontournable pour chaque DBA MySQL).
pt-show-grants --host localhost --user root --ask-pass
Alternativement, vous pouvez utiliser la requête suivante (créée par Calvaldo)
SELECT
CONCAT("`",gcl.Db,"`") AS 'Database(s) Affected',
CONCAT("`",gcl.Table_name,"`") AS 'Table(s) Affected',
gcl.User AS 'User-Account(s) Affected',
IF(gcl.Host='%','ALL',gcl.Host) AS 'Remote-IP(s) Affected',
CONCAT("GRANT ",UPPER(gcl.Column_priv)," (",GROUP_CONCAT(gcl.Column_name),") ",
"ON `",gcl.Db,"`.`",gcl.Table_name,"` ",
"TO '",gcl.User,"'@'",gcl.Host,"';") AS 'GRANT Statement (Reconstructed)'
FROM mysql.columns_priv gcl
GROUP BY CONCAT(gcl.Db,gcl.Table_name,gcl.User,gcl.Host)
/* SELECT * FROM mysql.columns_priv */
UNION
/* [Database.Table]-Specific Grants */
SELECT
CONCAT("`",gtb.Db,"`") AS 'Database(s) Affected',
CONCAT("`",gtb.Table_name,"`") AS 'Table(s) Affected',
gtb.User AS 'User-Account(s) Affected',
IF(gtb.Host='%','ALL',gtb.Host) AS 'Remote-IP(s) Affected',
CONCAT(
"GRANT ",UPPER(gtb.Table_priv)," ",
"ON `",gtb.Db,"`.`",gtb.Table_name,"` ",
"TO '",gtb.User,"'@'",gtb.Host,"';"
) AS 'GRANT Statement (Reconstructed)'
FROM mysql.tables_priv gtb
WHERE gtb.Table_priv!=''
/* SELECT * FROM mysql.tables_priv */
UNION
/* Database-Specific Grants */
SELECT
CONCAT("`",gdb.Db,"`") AS 'Database(s) Affected',
"ALL" AS 'Table(s) Affected',
gdb.User AS 'User-Account(s) Affected',
IF(gdb.Host='%','ALL',gdb.Host) AS 'Remote-IP(s) Affected',
CONCAT(
'GRANT ',
CONCAT_WS(',',
IF(gdb.Select_priv='Y','SELECT',NULL),
IF(gdb.Insert_priv='Y','INSERT',NULL),
IF(gdb.Update_priv='Y','UPDATE',NULL),
IF(gdb.Delete_priv='Y','DELETE',NULL),
IF(gdb.Create_priv='Y','CREATE',NULL),
IF(gdb.Drop_priv='Y','DROP',NULL),
IF(gdb.Grant_priv='Y','GRANT',NULL),
IF(gdb.References_priv='Y','REFERENCES',NULL),
IF(gdb.Index_priv='Y','INDEX',NULL),
IF(gdb.Alter_priv='Y','ALTER',NULL),
IF(gdb.Create_tmp_table_priv='Y','CREATE TEMPORARY TABLES',NULL),
IF(gdb.Lock_tables_priv='Y','LOCK TABLES',NULL),
IF(gdb.Create_view_priv='Y','CREATE VIEW',NULL),
IF(gdb.Show_view_priv='Y','SHOW VIEW',NULL),
IF(gdb.Create_routine_priv='Y','CREATE ROUTINE',NULL),
IF(gdb.Alter_routine_priv='Y','ALTER ROUTINE',NULL),
IF(gdb.Execute_priv='Y','EXECUTE',NULL),
IF(gdb.Event_priv='Y','EVENT',NULL),
IF(gdb.Trigger_priv='Y','TRIGGER',NULL)
),
" ON `",gdb.Db,"`.* TO '",gdb.User,"'@'",gdb.Host,"';"
) AS 'GRANT Statement (Reconstructed)'
FROM mysql.db gdb
WHERE gdb.Db != ''
/* SELECT * FROM mysql.db */
UNION
/* User-Specific Grants */
SELECT
"ALL" AS 'Database(s) Affected',
"ALL" AS 'Table(s) Affected',
gus.User AS 'User-Account(s) Affected',
IF(gus.Host='%','ALL',gus.Host) AS 'Remote-IP(s) Affected',
CONCAT(
"GRANT ",
IF((gus.Select_priv='N')&(gus.Insert_priv='N')&(gus.Update_priv='N')&(gus.Delete_priv='N')&(gus.Create_priv='N')&(gus.Drop_priv='N')&(gus.Reload_priv='N')&(gus.Shutdown_priv='N')&(gus.Process_priv='N')&(gus.File_priv='N')&(gus.References_priv='N')&(gus.Index_priv='N')&(gus.Alter_priv='N')&(gus.Show_db_priv='N')&(gus.Super_priv='N')&(gus.Create_tmp_table_priv='N')&(gus.Lock_tables_priv='N')&(gus.Execute_priv='N')&(gus.Repl_slave_priv='N')&(gus.Repl_client_priv='N')&(gus.Create_view_priv='N')&(gus.Show_view_priv='N')&(gus.Create_routine_priv='N')&(gus.Alter_routine_priv='N')&(gus.Create_user_priv='N')&(gus.Event_priv='N')&(gus.Trigger_priv='N')&(gus.Create_tablespace_priv='N')&(gus.Grant_priv='N'),
"USAGE",
IF((gus.Select_priv='Y')&(gus.Insert_priv='Y')&(gus.Update_priv='Y')&(gus.Delete_priv='Y')&(gus.Create_priv='Y')&(gus.Drop_priv='Y')&(gus.Reload_priv='Y')&(gus.Shutdown_priv='Y')&(gus.Process_priv='Y')&(gus.File_priv='Y')&(gus.References_priv='Y')&(gus.Index_priv='Y')&(gus.Alter_priv='Y')&(gus.Show_db_priv='Y')&(gus.Super_priv='Y')&(gus.Create_tmp_table_priv='Y')&(gus.Lock_tables_priv='Y')&(gus.Execute_priv='Y')&(gus.Repl_slave_priv='Y')&(gus.Repl_client_priv='Y')&(gus.Create_view_priv='Y')&(gus.Show_view_priv='Y')&(gus.Create_routine_priv='Y')&(gus.Alter_routine_priv='Y')&(gus.Create_user_priv='Y')&(gus.Event_priv='Y')&(gus.Trigger_priv='Y')&(gus.Create_tablespace_priv='Y')&(gus.Grant_priv='Y'),
"ALL PRIVILEGES",
CONCAT_WS(',',
IF(gus.Select_priv='Y','SELECT',NULL),
IF(gus.Insert_priv='Y','INSERT',NULL),
IF(gus.Update_priv='Y','UPDATE',NULL),
IF(gus.Delete_priv='Y','DELETE',NULL),
IF(gus.Create_priv='Y','CREATE',NULL),
IF(gus.Drop_priv='Y','DROP',NULL),
IF(gus.Reload_priv='Y','RELOAD',NULL),
IF(gus.Shutdown_priv='Y','SHUTDOWN',NULL),
IF(gus.Process_priv='Y','PROCESS',NULL),
IF(gus.File_priv='Y','FILE',NULL),
IF(gus.References_priv='Y','REFERENCES',NULL),
IF(gus.Index_priv='Y','INDEX',NULL),
IF(gus.Alter_priv='Y','ALTER',NULL),
IF(gus.Show_db_priv='Y','SHOW DATABASES',NULL),
IF(gus.Super_priv='Y','SUPER',NULL),
IF(gus.Create_tmp_table_priv='Y','CREATE TEMPORARY TABLES',NULL),
IF(gus.Lock_tables_priv='Y','LOCK TABLES',NULL),
IF(gus.Execute_priv='Y','EXECUTE',NULL),
IF(gus.Repl_slave_priv='Y','REPLICATION SLAVE',NULL),
IF(gus.Repl_client_priv='Y','REPLICATION CLIENT',NULL),
IF(gus.Create_view_priv='Y','CREATE VIEW',NULL),
IF(gus.Show_view_priv='Y','SHOW VIEW',NULL),
IF(gus.Create_routine_priv='Y','CREATE ROUTINE',NULL),
IF(gus.Alter_routine_priv='Y','ALTER ROUTINE',NULL),
IF(gus.Create_user_priv='Y','CREATE USER',NULL),
IF(gus.Event_priv='Y','EVENT',NULL),
IF(gus.Trigger_priv='Y','TRIGGER',NULL),
IF(gus.Create_tablespace_priv='Y','CREATE TABLESPACE',NULL)
)
)
),
" ON *.* TO '",gus.User,"'@'",gus.Host,"' REQUIRE ",
CASE gus.ssl_type
WHEN 'ANY' THEN
"SSL "
WHEN 'X509' THEN
"X509 "
WHEN 'SPECIFIED' THEN
CONCAT_WS("AND ",
IF((LENGTH(gus.ssl_cipher)>0),CONCAT("CIPHER '",CONVERT(gus.ssl_cipher USING utf8),"' "),NULL),
IF((LENGTH(gus.x509_issuer)>0),CONCAT("ISSUER '",CONVERT(gus.ssl_cipher USING utf8),"' "),NULL),
IF((LENGTH(gus.x509_subject)>0),CONCAT("SUBJECT '",CONVERT(gus.ssl_cipher USING utf8),"' "),NULL)
)
ELSE "NONE "
END,
"WITH ",
IF(gus.Grant_priv='Y',"GRANT OPTION ",""),
"MAX_QUERIES_PER_HOUR ",gus.max_questions," ",
"MAX_CONNECTIONS_PER_HOUR ",gus.max_connections," ",
"MAX_UPDATES_PER_HOUR ",gus.max_updates," ",
"MAX_USER_CONNECTIONS ",gus.max_user_connections,
";"
) AS 'GRANT Statement (Reconstructed)'
FROM mysql.user gus;
Comment créer un utilisateur mysql
La procédure "Créer un utilisateur" est similaire à Oracle. L'exemple le plus simple pourrait être :
CREATE user 'username'@'hostname' identified by 'password';
GRANT privilege_name on *.* TO 'username'@'hostname';
L'option d'accorder et de créer en une seule ligne avec :
GRANT privilege_name ON *.* TO 'username'@'hostname' identified by 'password';
a été supprimé dans MySQL 8.0.
Comment démarrer et arrêter MySQL ?
Vous pouvez arrêter et démarrer MySQL avec le service.
La commande réelle dépend de la distribution Linux et du nom du service.
Vous trouverez ci-dessous un exemple avec le nom de service mysqld.
Ubuntu
/etc/init.d/mysqld start
/etc/init.d/mysqld stop
/etc/init.d/mysqld restart
RedHat/Centos
service mysqld start
service mysqld stop
service mysqld restart
systemctl start mysqld.service
systemctl stop mysqld.service
systemctl restart mysqld.service
Où se trouvent les données de configuration du serveur MySQL ?
La configuration est stockée dans le fichier my.cnf.
Jusqu'à la version 8.0, toute modification de paramètre dynamique qui devait rester après un redémarrage nécessitait une mise à jour manuelle du fichier my.cnf. Semblable à scope=both d'Oracle, vous pouvez modifier les valeurs à l'aide de l'option persistante.
mysql> SET PERSIST max_connections = 1000;
mysql> SET @@PERSIST.max_connections = 1000;
Pour les anciennes versions, utilisez :
mysql> SET GLOBAL max_connections = 1000;
$ vi /etc/mysql/my.cnf
SET GLOBAL max_connections = 1000;
Comment sauvegarder MySQL ?
Il existe deux façons d'exécuter une sauvegarde mysql.
Pour les bases de données plus petites ou les sauvegardes sélectives plus petites, vous pouvez utiliser la commande mysqldump.
Sauvegarde de la base de données avec mysqldump (sauvegarde logique) :
mysqldump -uuser -p --databases db_name --routines --events --single-transaction | gzip > db_name_backup.sql.gz
xtrabackup, mariabackup (sauvegarde binaire à chaud)
La méthode préférable consiste à utiliser xtrabackup ou mariabackup, des outils externes pour exécuter des sauvegardes binaires à chaud.
Oracle propose une sauvegarde binaire à chaud dans la version payante appelée MySQL Enterprise Edition.
mariabackup --user=root --password=PASSWORD --backup --target-dir=/u01/backups/
Sauvegarde en streaming sur un autre serveur
Démarrez un écouteur sur le serveur externe sur le port préférable (dans cet exemple 1984)
nc -l 1984 | pigz -cd - | pv | xbstream -x -C /u01/backups
Exécuter la sauvegarde et le transfert vers un hôte externe
innobackupex --user=root --password=PASSWORD --stream=xbstream /var/tmp | pigz | pv | nc external_host.com 1984
Copier l'autorisation de l'utilisateur
Il est souvent nécessaire de copier les autorisations des utilisateurs et de les transférer vers les autres serveurs.
La méthode recommandée pour ce faire est d'utiliser pt-show-grants.
pt-show-grants > /u01/backups
Comment restaurer MySQL ?
Restauration de sauvegarde logique
MySQLdump crée le fichier SQL, qui peut être exécuté avec la commande source.
Pour conserver le fichier journal de l'exécution, utilisez la commande tee.
mysql> tee dump.log
mysql> source mysqldump.sql
Restauration de sauvegarde binaire (xtrabackup/mariabackup)
Pour restaurer MySQL à partir de la sauvegarde binaire, vous devez d'abord restaurer les fichiers, puis appliquer les fichiers journaux.
Vous pouvez comparer ce processus pour restaurer et récupérer dans Oracle.
xtrabackup --copy-back --target-dir=/var/lib/data
innobackupex --apply-log --use-memory=[values in MB or GB] /var/lib/data
Espérons que ces conseils donnent un bon aperçu de la façon d'effectuer des tâches administratives de base.