Mysql
 sql >> Base de Dados >  >> RDS >> Mysql

Como gerenciar o MySQL - para DBAs Oracle


Os bancos de dados de código aberto estão rapidamente se tornando populares, portanto, a migração de mecanismos proprietários para mecanismos de código aberto é uma espécie de tendência do setor agora. Isso também significa que nós, DBAs, muitas vezes acabamos tendo vários back-ends de banco de dados para gerenciar.

Nas últimas postagens do blog, meu colega Paul Namuag e eu abordamos vários aspectos da migração do Oracle para Percona, MariaDB e MySQL. O objetivo óbvio da migração é fazer com que seu aplicativo funcione com mais eficiência no novo ambiente de banco de dados, no entanto, é crucial garantir que a equipe esteja pronta para apoiá-lo.

Este blog aborda as operações básicas do MySQL com referência a tarefas semelhantes que você executaria diariamente em seu ambiente Oracle. Ele fornece um mergulho profundo em diferentes tópicos para economizar tempo, pois você pode se relacionar com o conhecimento Oracle que já construiu ao longo dos anos.

Também falaremos sobre ferramentas externas de linha de comando que estão faltando na instalação padrão do MySQL, mas são necessárias para realizar operações diárias com eficiência. A versão de código aberto não vem com o equivalente do Oracle Cloud Control, por exemplo, então faça o checkout do ClusterControl se estiver procurando por algo semelhante.

Neste blog, estamos assumindo que você tem um conhecimento melhor de Oracle do que MySQL e, portanto, gostaria de saber a correlação entre os dois. Os exemplos são baseados na plataforma Linux, mas você pode encontrar muitas semelhanças no gerenciamento do MySQL no Windows.

Como me conecto ao MySQL?


Vamos começar nossa jornada com uma tarefa muito (aparentemente) básica. Na verdade, este é um tipo de tarefa que pode causar alguma confusão devido aos diferentes conceitos de login no Oracle e no MySQL.

O equivalente à conexão sqlplus / as sysdba é o comando de terminal “mysql” com um sinalizador -uroot. No mundo MySQL, o superusuário é chamado de root. Os usuários do banco de dados MySQL (incluindo root) são definidos pelo nome e host de onde ele pode se conectar.

As informações sobre usuário e hosts de onde ele pode se conectar são armazenadas na tabela mysql.user. Com a tentativa de conexão, o MySQL verifica se o host do cliente, nome de usuário e senha correspondem à linha na tabela de metadados.

Essa é uma abordagem um pouco diferente da Oracle, onde temos apenas um nome de usuário e senha, mas aqueles que estão familiarizados com o Oracle Connection Manager podem encontrar algumas semelhanças.

Você não encontrará entradas TNS predefinidas como no Oracle. Normalmente, para uma conexão de administrador, precisamos de usuário, senha e sinalizador de host -h. A porta padrão é 3306 (como 1521 no Oracle), mas isso pode variar em diferentes configurações.

Por padrão, muitas instalações terão a conexão de acesso root de qualquer máquina ([email protected]’%’) bloqueada, então você precisa fazer login no servidor que hospeda o MySQL, normalmente via ssh.

Digite o seguinte:
mysql -u root

Quando a senha de root não está definida, isso é suficiente. Se a senha for necessária, você deve adicionar o sinalizador -p.
mysql -u root -p

Agora você está logado no cliente mysql (o equivalente a sqlplus) e verá um prompt, normalmente 'mysql>'.

O MySQL está funcionando?


Você pode usar o script de inicialização do serviço mysql ou o comando mysqladmin para descobrir se ele está sendo executado. Então você pode usar o comando ps para ver se os processos do mysql estão funcionando. Outra alternativa pode ser mysqladmin, que é um utilitário usado para realizar operações administrativas.
mysqladmin -u root -p status

No Debian:
/etc/init.d/mysql status

Se você estiver usando RedHat ou Fedora, poderá usar o seguinte script:
service mysqld status

Ou
/etc/init.d/mysqld status

Ou
systemctl status mysql.service

Em instâncias MariaDB, você deve procurar o nome do serviço MariaDB.
systemctl status mariadb

O que há neste banco de dados?


Como no Oracle, você pode consultar os objetos de metadados para obter informações sobre os objetos do banco de dados.

É comum usar alguns atalhos aqui, comandos que ajudam você a listar objetos ou obter DDL dos objetos.
show databases;
use database_name;
show tables;
show table status;
show index from table_name;
show create table table_name;

Semelhante ao Oracle, você pode descrever a tabela:
desc table_name;

Onde meus dados estão armazenados?


Não há armazenamento interno dedicado como o ASM no MySQL. Todos os arquivos de dados são colocados nos pontos de montagem regulares do SO. Com uma instalação padrão, você pode encontrar seus dados em:
/var/lib/mysql

A localização é baseada na variável datadir.
[email protected]:~# cat /etc/mysql/my.cnf | grep datadir
datadir=/var/lib/mysql

Você verá lá um diretório para cada banco de dados.

Dependendo da versão e do mecanismo de armazenamento (sim, existem alguns aqui), o diretório do banco de dados pode conter arquivos no formato *.frm, que definem a estrutura de cada tabela dentro do banco de dados. Para tabelas MyISAM, os dados (*.MYD) e índices (*.MYI) também são armazenados neste diretório.

As tabelas InnoDB são armazenadas em espaços de tabela InnoDB. Cada um deles consiste em um ou mais arquivos, que são semelhantes aos tablespaces do Oracle. Em uma instalação padrão, todos os dados e índices do InnoDB para todos os bancos de dados em um servidor MySQL são mantidos em um tablespace, consistindo em um arquivo:/var/lib/mysql/ibdata1. Na maioria das configurações, você não gerencia tablespaces como no Oracle. A melhor prática é mantê-los com autoextend ativado e tamanho máximo ilimitado.
[email protected]:~# cat /etc/mysql/my.cnf | grep innodb-data-file-path
innodb-data-file-path = ibdata1:100M:autoextend

O InnoDB possui arquivos de log, que são equivalentes aos redo logs do Oracle, permitindo a recuperação automática de falhas. Por padrão, existem dois arquivos de log:/var/lib/mysql/ib_logfile0 e /var/lib/mysql/ib_logfile1. Os dados de desfazer são mantidos no arquivo de 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

Onde estão as informações de metadados?


Não existem visualizações do tipo dba_*, user_*, all_*, mas o MySQL possui visualizações internas de metadados.

Information_schema é definido no padrão SQL 2003 e é implementado por outros bancos de dados importantes, por exemplo, SQL Server, PostgreSQL.

Desde o MySQL 5.0, o banco de dados information_schema está disponível, contendo informações do dicionário de dados. As informações foram realmente armazenadas nos arquivos FRM externos. Finalmente, depois de muitos anos, os arquivos .frm desapareceram na versão 8.0. Os metadados ainda estão visíveis no banco de dados information_schema, mas usam o mecanismo de armazenamento InnoDB.

Para ver todas as visualizações reais contidas no dicionário de dados no cliente mysql, alterne para o banco de dados information_schema:
use information_schema;
show tables;

Você pode encontrar informações adicionais no banco de dados MySQL, que contém informações sobre db, evento (trabalhos MySQL), plugins, replicação, banco de dados, usuários etc.

O número de visualizações depende da versão e do fornecedor.

Selecione * de v$session


O select * da v$session do Oracle é representado aqui com o comando SHOW PROCESSLIST que mostra a lista de 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)

Ele é baseado em informações armazenadas na visualização information_schema.processlist. A visualização requer o privilégio PROCESS. Ele também pode ajudá-lo a verificar se você está ficando sem o número máximo de processos.

Onde está um registro de alerta?


O log de erros pode ser encontrado em my.cnf ou via 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)

Onde está a lista de usuários e suas permissões?


As informações sobre os usuários são armazenadas na tabela mysql.user, enquanto as concessões são armazenadas em vários locais, incluindo mysql.user, mysql.tables_priv,

O acesso do usuário MySQL é definido em:
mysql.columns_priv, mysql.tables_priv, mysql.db,mysql.user

A maneira preferível de listar concessões é usar pt-grants, a ferramenta do kit de ferramentas Percona (indispensável para todo DBA MySQL).
pt-show-grants --host localhost --user root --ask-pass

Alternativamente, você pode usar a seguinte consulta (criada 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;

Como criar um usuário mysql


O procedimento 'criar usuário' é semelhante ao Oracle. O exemplo mais simples poderia ser:
CREATE user 'username'@'hostname' identified by 'password';
GRANT privilege_name on *.* TO 'username'@'hostname';

A opção de conceder e criar em uma linha com:
GRANT privilege_name  ON *.* TO 'username'@'hostname' identified by 'password';

foi removido no MySQL 8.0.

Como inicio e paro o MySQL?


Você pode parar e iniciar o MySQL com o serviço.

O comando real depende da distribuição Linux e do nome do serviço.

Abaixo você pode encontrar um exemplo com o nome do serviço 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

Onde estão os dados de configuração do servidor MySQL?


A configuração é armazenada no arquivo my.cnf.

Até a versão 8.0, qualquer alteração de configuração dinâmica que deveria permanecer após uma reinicialização exigia uma atualização manual do arquivo my.cnf. Semelhante ao scope=both do Oracle, você pode alterar os valores usando a opção persistente.
mysql> SET PERSIST max_connections = 1000;
mysql> SET @@PERSIST.max_connections = 1000;

Para versões mais antigas, use:
mysql> SET GLOBAL max_connections = 1000;
$ vi /etc/mysql/my.cnf
SET GLOBAL max_connections = 1000;

Como faço backup do MySQL?


Existem duas maneiras de executar um backup do mysql.

Para bancos de dados menores ou backups seletivos menores, você pode usar o comando mysqldump.

Backup de banco de dados com mysqldump (backup lógico):

mysqldump -uuser -p --databases db_name --routines --events --single-transaction | gzip > db_name_backup.sql.gz

xtrabackup, mariabackup (backup binário dinâmico)


O método preferível é usar xtrabackup ou mariabackup, ferramentas externas para executar backups binários quentes.

A Oracle oferece backup binário quente na versão paga chamada MySQL Enterprise Edition.
mariabackup --user=root --password=PASSWORD --backup --target-dir=/u01/backups/

Transmitir backup para outro servidor


Inicie um ouvinte no servidor externo na porta preferencial (neste exemplo 1984)
nc -l 1984 | pigz -cd - | pv | xbstream -x -C /u01/backups

Execute o backup e transfira para o host externo
innobackupex --user=root --password=PASSWORD --stream=xbstream /var/tmp | pigz  | pv | nc external_host.com 1984

Copiar permissão do usuário


Muitas vezes é necessário copiar a permissão do usuário e transferi-la para outros servidores.

A maneira recomendada de fazer isso é usar pt-show-grants.
pt-show-grants > /u01/backups

Como faço para restaurar o MySQL?

Restauração de backup lógico


MySQLdump cria o arquivo SQL, que pode ser executado com o comando source.

Para manter o arquivo de log da execução, use o comando tee.
mysql> tee dump.log
mysql> source mysqldump.sql

Restauração de backup binário (xtrabackup/mariabackup)


Para restaurar o MySQL a partir do backup binário, você precisa primeiro restaurar os arquivos e depois aplicar os arquivos de log.

Você pode comparar esse processo para restaurar e recuperar no Oracle.
xtrabackup --copy-back --target-dir=/var/lib/data
innobackupex --apply-log --use-memory=[values in MB or GB] /var/lib/data

Felizmente, essas dicas fornecem uma boa visão geral de como executar tarefas administrativas básicas.