Las bases de datos de código abierto se están convirtiendo rápidamente en la corriente principal, por lo que la migración de motores patentados a motores de código abierto es una especie de tendencia de la industria ahora. También significa que nosotros, los administradores de bases de datos, a menudo terminamos teniendo múltiples backends de bases de datos para administrar.
En las últimas publicaciones de blog, mi colega Paul Namuag y yo cubrimos varios aspectos de la migración de Oracle a Percona, MariaDB y MySQL. El objetivo obvio de la migración es hacer que su aplicación funcione de manera más eficiente en el nuevo entorno de la base de datos, sin embargo, es crucial asegurarse de que el personal esté listo para brindarle soporte.
Este blog cubre las operaciones básicas de MySQL con referencia a tareas similares que realizaría diariamente en su entorno de Oracle. Le brinda una inmersión profunda en diferentes temas para ahorrarle tiempo, ya que puede relacionarse con el conocimiento de Oracle que ya ha desarrollado a lo largo de los años.
También hablaremos sobre las herramientas de línea de comandos externas que faltan en la instalación predeterminada de MySQL pero que son necesarias para realizar las operaciones diarias de manera eficiente. La versión de código abierto no viene con el equivalente de Oracle Cloud Control, por ejemplo, así que consulte ClusterControl si está buscando algo similar.
En este blog, asumimos que tiene un mejor conocimiento de Oracle que de MySQL y, por lo tanto, le gustaría saber la correlación entre los dos. Los ejemplos se basan en la plataforma Linux; sin embargo, puede encontrar muchas similitudes en la administración de MySQL en Windows.
¿Cómo me conecto a MySQL?
Comencemos nuestro viaje con una tarea muy (aparentemente) básica. En realidad, este es un tipo de tarea que puede causar cierta confusión debido a los diferentes conceptos de inicio de sesión en Oracle y MySQL.
El equivalente de la conexión sqlplus / as sysdba es el comando de terminal "mysql" con un indicador -uroot. En el mundo de MySQL, el superusuario se llama root. Los usuarios de la base de datos MySQL (incluido el root) se definen por el nombre y el host desde donde se puede conectar.
La información sobre el usuario y los hosts desde donde se puede conectar se almacena en la tabla mysql.user. Con el intento de conexión, MySQL comprueba si el host del cliente, el nombre de usuario y la contraseña coinciden con la fila de la tabla de metadatos.
Este es un enfoque un poco diferente al de Oracle, donde solo tenemos un nombre de usuario y una contraseña, pero aquellos que están familiarizados con Oracle Connection Manager pueden encontrar algunas similitudes.
No encontrará entradas TNS predefinidas como en Oracle. Por lo general, para una conexión de administrador, necesitamos el usuario, la contraseña y el indicador de host -h. El puerto predeterminado es 3306 (como 1521 en Oracle), pero esto puede variar en diferentes configuraciones.
De forma predeterminada, muchas instalaciones tendrán bloqueada la conexión de acceso raíz desde cualquier máquina ([email protected]'%'), por lo que debe iniciar sesión en el servidor que aloja MySQL, generalmente a través de ssh.
Escribe lo siguiente:
mysql -u root
Cuando la contraseña de root no está configurada, esto es suficiente. Si se requiere la contraseña, debe agregar la marca -p.
mysql -u root -p
Ahora ha iniciado sesión en el cliente mysql (el equivalente de sqlplus) y verá un mensaje, normalmente 'mysql>'.
¿Está MySQL funcionando?
Puede usar el script de inicio del servicio mysql o el comando mysqladmin para averiguar si se está ejecutando. Luego puede usar el comando ps para ver si los procesos de mysql están funcionando. Otra alternativa puede ser mysqladmin, que es una utilidad que se utiliza para realizar operaciones administrativas.
mysqladmin -u root -p status
En Debian:
/etc/init.d/mysql status
Si está usando RedHat o Fedora, puede usar el siguiente script:
service mysqld status
O
/etc/init.d/mysqld status
O
systemctl status mysql.service
En las instancias de MariaDB, debe buscar el nombre del servicio de MariaDB.
systemctl status mariadb
¿Qué hay en esta base de datos?
Al igual que en Oracle, puede consultar los objetos de metadatos para obtener información sobre los objetos de la base de datos.
Es común usar algunos atajos aquí, comandos que lo ayudan a enumerar objetos u obtener DDL de los objetos.
show databases;
use database_name;
show tables;
show table status;
show index from table_name;
show create table table_name;
Similar a Oracle, puede describir la tabla:
desc table_name;
¿Dónde se almacenan mis datos?
No hay almacenamiento interno dedicado como ASM en MySQL. Todos los archivos de datos se colocan en los puntos de montaje regulares del sistema operativo. Con una instalación predeterminada, puede encontrar sus datos en:
/var/lib/mysql
La ubicación se basa en la variable datadir.
[email protected]:~# cat /etc/mysql/my.cnf | grep datadir
datadir=/var/lib/mysql
Verá allí un directorio para cada base de datos.
Dependiendo de la versión y el motor de almacenamiento (sí, hay algunos aquí), el directorio de la base de datos puede contener archivos de formato *.frm, que definen la estructura de cada tabla dentro de la base de datos. Para las tablas MyISAM, los datos (*.MYD) y los índices (*.MYI) también se almacenan dentro de este directorio.
Las tablas de InnoDB se almacenan en espacios de tablas de InnoDB. Cada uno de los cuales consta de uno o más archivos, que son similares a los espacios de tablas de Oracle. En una instalación predeterminada, todos los datos e índices de InnoDB para todas las bases de datos en un servidor MySQL se mantienen en un espacio de tabla, que consta de un archivo:/var/lib/mysql/ibdata1. En la mayoría de las configuraciones, no administra espacios de tabla como en Oracle. La mejor práctica es mantenerlos con la extensión automática activada y el tamaño máximo ilimitado.
[email protected]:~# cat /etc/mysql/my.cnf | grep innodb-data-file-path
innodb-data-file-path = ibdata1:100M:autoextend
InnoDB tiene archivos de registro, que son el equivalente a los registros de rehacer de Oracle, lo que permite la recuperación automática de fallas. De forma predeterminada, hay dos archivos de registro:/var/lib/mysql/ib_logfile0 y /var/lib/mysql/ib_logfile1. Los datos de deshacer se mantienen dentro del archivo tablespace.
[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
¿Dónde está la información de metadatos?
No hay vistas de tipo dba_*, user_*, all_*, pero MySQL tiene vistas internas de metadatos.
Information_schema se define en el estándar SQL 2003 y se implementa en otras bases de datos importantes, p. Servidor SQL, PostgreSQL.
Desde MySQL 5.0, la base de datos information_schema ha estado disponible y contiene información del diccionario de datos. La información en realidad se almacenó en los archivos FRM externos. Finalmente, después de muchos años, los archivos .frm desaparecieron en la versión 8.0. Los metadatos siguen estando visibles en la base de datos information_schema pero utilizan el motor de almacenamiento InnoDB.
Para ver todas las vistas reales contenidas en el diccionario de datos dentro del cliente mysql, cambie a la base de datos information_schema:
use information_schema;
show tables;
Puede encontrar información adicional en la base de datos MySQL, que contiene información sobre db, eventos (trabajos de MySQL), complementos, replicación, base de datos, usuarios, etc.
El número de vistas depende de la versión y el proveedor.
Seleccione * de v$sesión
La selección * de v$session de Oracle se representa aquí con el comando MOSTRAR LISTA DE PROCESOS que muestra la lista de subprocesos.
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)
Se basa en la información almacenada en la vista information_schema.processlist. La vista requiere tener el privilegio PROCESS. También puede ayudarlo a verificar si se está quedando sin la cantidad máxima de procesos.
¿Dónde se encuentra un registro de alertas?
El registro de errores se puede encontrar en my.cnf o a través del comando 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)
¿Dónde está la lista de usuarios y sus permisos?
La información sobre los usuarios se almacena en la tabla mysql.user, mientras que las concesiones se almacenan en varios lugares, incluidos mysql.user, mysql.tables_priv,
El acceso de usuario de MySQL se define en:
mysql.columns_priv, mysql.tables_priv, mysql.db,mysql.user
La forma preferible de enumerar las subvenciones es usar pt-grants, la herramienta del kit de herramientas de Percona (imprescindible para todos los administradores de bases de datos de MySQL).
pt-show-grants --host localhost --user root --ask-pass
Alternativamente, puede usar la siguiente consulta (creada por 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;
Cómo crear un usuario mysql
El procedimiento de 'crear usuario' es similar a Oracle. El ejemplo más simple podría ser:
CREATE user 'username'@'hostname' identified by 'password';
GRANT privilege_name on *.* TO 'username'@'hostname';
La opción de otorgar y crear en una línea con:
GRANT privilege_name ON *.* TO 'username'@'hostname' identified by 'password';
ha sido eliminado en MySQL 8.0.
¿Cómo inicio y detengo MySQL?
Puede detener e iniciar MySQL con el servicio.
El comando real depende de la distribución de Linux y el nombre del servicio.
A continuación puede encontrar un ejemplo con el nombre de servicio 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
¿Dónde están los datos de configuración del servidor MySQL?
La configuración se almacena en el archivo my.cnf.
Hasta la versión 8.0, cualquier cambio de configuración dinámica que deba permanecer después de un reinicio requería una actualización manual del archivo my.cnf. Similar a scope=both de Oracle, puede cambiar valores usando la opción persistente.
mysql> SET PERSIST max_connections = 1000;
mysql> SET @@PERSIST.max_connections = 1000;
Para versiones anteriores use:
mysql> SET GLOBAL max_connections = 1000;
$ vi /etc/mysql/my.cnf
SET GLOBAL max_connections = 1000;
¿Cómo hago una copia de seguridad de MySQL?
Hay dos formas de ejecutar una copia de seguridad de mysql.
Para bases de datos más pequeñas o copias de seguridad selectivas más pequeñas, puede usar el comando mysqldump.
Copia de seguridad de la base de datos con mysqldump (copia de seguridad lógica):
mysqldump -uuser -p --databases db_name --routines --events --single-transaction | gzip > db_name_backup.sql.gz
xtrabackup, mariabackup (copia de seguridad binaria activa)
El método preferible es utilizar xtrabackup o mariabackup, herramientas externas para ejecutar copias de seguridad binarias activas.
Oracle ofrece copia de seguridad binaria caliente en la versión paga llamada MySQL Enterprise Edition.
mariabackup --user=root --password=PASSWORD --backup --target-dir=/u01/backups/
Transmitir copia de seguridad a otro servidor
Inicie un oyente en el servidor externo en el puerto preferible (en este ejemplo, 1984)
nc -l 1984 | pigz -cd - | pv | xbstream -x -C /u01/backups
Ejecute la copia de seguridad y transfiera a un host externo
innobackupex --user=root --password=PASSWORD --stream=xbstream /var/tmp | pigz | pv | nc external_host.com 1984
Copiar permiso de usuario
A menudo es necesario copiar los permisos de los usuarios y transferirlos a otros servidores.
La forma recomendada de hacer esto es usar pt-show-grants.
pt-show-grants > /u01/backups
¿Cómo restauro MySQL?
Restauración de copia de seguridad lógica
MySQLdump crea el archivo SQL, que se puede ejecutar con el comando fuente.
Para mantener el archivo de registro de la ejecución, use el comando tee.
mysql> tee dump.log
mysql> source mysqldump.sql
Restauración de copia de seguridad binaria (xtrabackup/mariabackup)
Para restaurar MySQL desde la copia de seguridad binaria, primero debe restaurar los archivos y luego aplicar los archivos de registro.
Puede comparar este proceso para restaurar y recuperar en Oracle.
xtrabackup --copy-back --target-dir=/var/lib/data
innobackupex --apply-log --use-memory=[values in MB or GB] /var/lib/data
Esperamos que estos consejos brinden una buena visión general de cómo realizar tareas administrativas básicas.