Mysql
 sql >> Database >  >> RDS >> Mysql

Come gestire MySQL - per i DBA Oracle

I database open source stanno rapidamente diventando mainstream, quindi la migrazione da motori proprietari a motori open source è ormai una sorta di tendenza del settore. Significa anche che noi DBA spesso finiamo per avere più backend di database da gestire.

Negli ultimi post del blog, io e il mio collega Paul Namuag abbiamo trattato diversi aspetti della migrazione da Oracle a Percona, MariaDB e MySQL. L'obiettivo ovvio della migrazione è rendere l'applicazione attiva e funzionante in modo più efficiente nel nuovo ambiente di database, tuttavia è fondamentale assicurarsi che il personale sia pronto a supportarla.

Questo blog copre le operazioni di base di MySQL con riferimento ad attività simili che eseguiresti quotidianamente nel tuo ambiente Oracle. Ti offre un approfondimento su diversi argomenti per farti risparmiare tempo in quanto puoi relazionarti con le conoscenze Oracle che hai già costruito nel corso degli anni.

Parleremo anche di strumenti da riga di comando esterni che mancano nell'installazione predefinita di MySQL ma sono necessari per eseguire le operazioni quotidiane in modo efficiente. La versione open source non viene fornita con l'equivalente di Oracle Cloud Control, ad esempio, quindi controlla ClusterControl se stai cercando qualcosa di simile.

In questo blog, presumiamo che tu abbia una migliore conoscenza di Oracle rispetto a MySQL e quindi vorremmo conoscere la correlazione tra i due. Gli esempi sono basati su piattaforma Linux, tuttavia puoi trovare molte somiglianze nella gestione di MySQL su Windows.

Come mi connetto a MySQL?

Iniziamo il nostro viaggio con un compito molto (apparentemente) di base. In realtà, questo è un tipo di attività che può creare confusione a causa dei diversi concetti di accesso in Oracle e MySQL.

L'equivalente di sqlplus / as sysdba connection è il comando terminale "mysql" con un flag -uroot. Nel mondo MySQL, il superutente è chiamato root. Gli utenti del database MySQL (incluso root) sono definiti dal nome e dall'host da cui possono connettersi.

Le informazioni sull'utente e sugli host da cui può connettersi sono archiviate nella tabella mysql.user. Con il tentativo di connessione, MySQL verifica se l'host del client, il nome utente e la password corrispondono alla riga nella tabella dei metadati.

Questo è un approccio leggermente diverso rispetto a Oracle, dove abbiamo solo un nome utente e una password, ma coloro che hanno familiarità con Oracle Connection Manager potrebbero trovare alcune somiglianze.

Non troverai voci TNS predefinite come in Oracle. Di solito, per una connessione di amministrazione, abbiamo bisogno di utente, password e flag host -h. La porta predefinita è 3306 (come 1521 in Oracle), ma può variare in base alle diverse configurazioni.

Per impostazione predefinita, molte installazioni avranno la connessione di accesso root da qualsiasi macchina ([email protected]'%') bloccata, quindi devi accedere al server che ospita MySQL, in genere tramite ssh.

Digita quanto segue:

mysql -u root

Quando la password di root non è impostata, questo è sufficiente. Se è richiesta la password, dovresti aggiungere il flag -p.

mysql -u root -p

Ora sei connesso al client mysql (l'equivalente di sqlplus) e vedrai un prompt, tipicamente 'mysql>'.

MySQL è attivo e funzionante?

È possibile utilizzare lo script di avvio del servizio mysql o il comando mysqladmin per scoprire se è in esecuzione. Quindi puoi usare il comando ps per vedere se i processi mysql sono attivi e in esecuzione. Un'altra alternativa può essere mysqladmin, che è un'utilità utilizzata per eseguire operazioni amministrative.

mysqladmin -u root -p status

Su Debian:

/etc/init.d/mysql status

Se stai usando RedHat o Fedora, puoi usare il seguente script:

service mysqld status

Oppure

/etc/init.d/mysqld status

Oppure

systemctl status mysql.service

Nelle istanze MariaDB, dovresti cercare il nome del servizio MariaDB.

systemctl status mariadb

Cosa c'è in questo database?

Come in Oracle, puoi interrogare gli oggetti dei metadati per ottenere informazioni sugli oggetti del database.

È comune usare qui alcune scorciatoie, comandi che ti aiutano a elencare oggetti o ottenere DDL degli oggetti.

show databases;
use database_name;
show tables;
show table status;
show index from table_name;
show create table table_name;

Simile a Oracle puoi descrivere la tabella:

desc table_name;

Dove sono archiviati i miei dati?

Non esiste una memoria interna dedicata come ASM in MySQL. Tutti i file di dati vengono inseriti nei normali punti di montaggio del sistema operativo. Con un'installazione predefinita, puoi trovare i tuoi dati in:

/var/lib/mysql

La posizione è basata sulla variabile datadir.

[email protected]:~# cat /etc/mysql/my.cnf | grep datadir
datadir=/var/lib/mysql

Vedrai lì una directory per ogni database.

A seconda della versione e del motore di archiviazione (sì, ce ne sono alcuni qui), la directory del database può contenere file del formato *.frm, che definiscono la struttura di ciascuna tabella all'interno del database. Per le tabelle MyISAM, anche i dati (*.MYD) e gli indici (*.MYI) sono archiviati in questa directory.

Le tabelle InnoDB sono archiviate nei tablespace InnoDB. Ciascuno dei quali è costituito da uno o più file, che sono simili ai tablespace Oracle. In un'installazione predefinita, tutti i dati e gli indici di InnoDB per tutti i database su un server MySQL sono conservati in un tablespace, costituito da un file:/var/lib/mysql/ibdata1. Nella maggior parte delle configurazioni, non gestisci i tablespace come in Oracle. La best practice è mantenerli con l'estensione automatica attiva e la dimensione massima illimitata.

[email protected]:~# cat /etc/mysql/my.cnf | grep innodb-data-file-path
innodb-data-file-path = ibdata1:100M:autoextend

InnoDB ha file di registro, che sono l'equivalente dei registri di ripristino di Oracle, consentendo il ripristino automatico del crash. Per impostazione predefinita sono presenti due file di registro:/var/lib/mysql/ib_logfile0 e /var/lib/mysql/ib_logfile1. I dati di annullamento vengono mantenuti all'interno del file 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

Dove sono le informazioni sui metadati?

Non ci sono viste di tipo dba_*, user_*, all_* ma MySQL ha viste di metadati interne.

Information_schema è definito nello standard SQL 2003 ed è implementato da altri database importanti, ad es. SQL Server, PostgreSQL.

Da MySQL 5.0 è disponibile il database information_schema, che contiene le informazioni del dizionario dei dati. Le informazioni sono state effettivamente memorizzate nei file FRM esterni. Finalmente, dopo molti anni i file .frm sono spariti nella versione 8.0. I metadati sono ancora visibili nel database information_schema ma utilizza il motore di archiviazione InnoDB.

Per vedere tutte le viste effettive contenute nel dizionario dei dati all'interno del client mysql, passa al database information_schema:

use information_schema;
show tables;

Puoi trovare ulteriori informazioni nel database MySQL, che contiene informazioni su db, eventi (lavori MySQL), plug-in, replica, database, utenti ecc.

Il numero di visualizzazioni dipende dalla versione e dal fornitore.

Seleziona * da v$session

La selezione di Oracle * da v$session è rappresentata qui con il comando SHOW PROCESSLIST che mostra l'elenco dei thread.

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)

Si basa sulle informazioni memorizzate nella vista information_schema.processlist. La vista richiede il privilegio PROCESS. Può anche aiutarti a verificare se stai esaurendo il numero massimo di processi.

Dov'è un registro avvisi?

Il registro degli errori può essere trovato in my.cnf o tramite il comando mostra variabili.

mysql> show variables like 'log_error';
+---------------+--------------------------+
| Variable_name | Value                    |
+---------------+--------------------------+
| log_error     | /var/lib/mysql/error.log |
+---------------+--------------------------+
1 row in set (0.00 sec)

Dov'è l'elenco degli utenti e le loro autorizzazioni?

Le informazioni sugli utenti sono archiviate nella tabella mysql.user, mentre le sovvenzioni sono archiviate in diversi posti tra cui mysql.user, mysql.tables_priv,

L'accesso utente MySQL è definito in:

mysql.columns_priv, mysql.tables_priv, mysql.db,mysql.user

Il modo migliore per elencare le sovvenzioni è utilizzare pt-grants, lo strumento di Percona toolkit (un must per ogni DBA MySQL).

pt-show-grants --host localhost --user root --ask-pass

In alternativa, puoi utilizzare la seguente query (creata da 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;

Come creare un utente MySQL

La procedura "crea utente" è simile a quella di Oracle. L'esempio più semplice potrebbe essere:

CREATE user 'username'@'hostname' identified by 'password';
GRANT privilege_name on *.* TO 'username'@'hostname';

L'opzione per concedere e creare in una riga con:

GRANT privilege_name  ON *.* TO 'username'@'hostname' identified by 'password';

è stato rimosso in MySQL 8.0.

Come si avvia e si arresta MySQL?

Puoi interrompere e avviare MySQL con il servizio.

Il comando effettivo dipende dalla distribuzione Linux e dal nome del servizio.

Di seguito puoi trovare un esempio con il nome del servizio 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

Dove sono i dati di configurazione del server MySQL?

La configurazione è salvata nel file my.cnf.

Fino alla versione 8.0, qualsiasi modifica dell'impostazione dinamica che dovesse rimanere dopo un riavvio richiedeva un aggiornamento manuale del file my.cnf. Simile a scope=entrambi di Oracle, puoi modificare i valori utilizzando l'opzione persistente.

mysql> SET PERSIST max_connections = 1000;
mysql> SET @@PERSIST.max_connections = 1000;

Per le versioni precedenti utilizzare:

mysql> SET GLOBAL max_connections = 1000;
$ vi /etc/mysql/my.cnf
SET GLOBAL max_connections = 1000;

Come si esegue il backup di MySQL?

Esistono due modi per eseguire un backup di MySQL.

Per database più piccoli o backup selettivi più piccoli, puoi utilizzare il comando mysqldump.

Backup del database con mysqldump (backup logico):

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

xtrabackup, mariabackup (backup binario a caldo)

Il metodo preferibile è utilizzare xtrabackup o mariabackup, strumenti esterni per eseguire backup binari a caldo.

Oracle offre il backup binario a caldo nella versione a pagamento denominata MySQL Enterprise Edition.

mariabackup --user=root --password=PASSWORD --backup --target-dir=/u01/backups/

Backup in streaming su altro server

Avvia un listener sul server esterno sulla porta preferita (in questo esempio 1984)

nc -l 1984 | pigz -cd - | pv | xbstream -x -C /u01/backups

Esegui il backup e trasferisci su un host esterno

innobackupex --user=root --password=PASSWORD --stream=xbstream /var/tmp | pigz  | pv | nc external_host.com 1984

Copia autorizzazione utente

Spesso è necessario copiare i permessi dell'utente e trasferirli sugli altri server.

Il modo consigliato per farlo è usare pt-show-grants.

pt-show-grants > /u01/backups

Come posso ripristinare MySQL?

Ripristino backup logico

MySQLdump crea il file SQL, che può essere eseguito con il comando sorgente.

Per conservare il file di registro dell'esecuzione, utilizzare il comando tee.

mysql> tee dump.log
mysql> source mysqldump.sql

Ripristino backup binario (xtrabackup/mariabackup)

Per ripristinare MySQL dal backup binario è necessario prima ripristinare i file e quindi applicare i file di registro.

Puoi confrontare questo processo con il ripristino e il ripristino in Oracle.

xtrabackup --copy-back --target-dir=/var/lib/data
innobackupex --apply-log --use-memory=[values in MB or GB] /var/lib/data

Si spera che questi suggerimenti forniscano una buona panoramica su come eseguire attività amministrative di base.