Open source-databaser er hurtigt ved at blive mainstream, så migrering fra proprietære motorer til open source-motorer er en slags branchetrend nu. Det betyder også, at vi DBA’er ofte ender med at have flere database backends at administrere.
I de sidste par blogindlæg har min kollega Paul Namuag og jeg dækket flere aspekter af migration fra Oracle til Percona, MariaDB og MySQL. Det åbenlyse mål for migreringen er at få din applikation op og køre mere effektivt i det nye databasemiljø, men det er afgørende at sikre, at personalet er klar til at støtte det.
Denne blog dækker de grundlæggende funktioner i MySQL med henvisning til lignende opgaver, som du ville udføre dagligt i dit Oracle-miljø. Det giver dig et dybt dyk i forskellige emner for at spare dig tid, da du kan relatere til Oracle-viden, som du allerede har opbygget gennem årene.
Vi vil også tale om eksterne kommandolinjeværktøjer, der mangler i standard MySQL-installationen, men som er nødvendige for at udføre daglige operationer effektivt. Open source-versionen kommer for eksempel ikke med det, der svarer til Oracle Cloud Control, så tjek ClusterControl, hvis du leder efter noget lignende.
I denne blog antager vi, at du har et bedre kendskab til Oracle end MySQL og derfor gerne vil kende sammenhængen mellem de to. Eksemplerne er baseret på Linux-platformen, men du kan finde mange ligheder i administration af MySQL på Windows.
Hvordan opretter jeg forbindelse til MySQL?
Lad os starte vores rejse med en meget (tilsyneladende) grundlæggende opgave. Faktisk er dette en slags opgave, der kan forårsage en vis forvirring på grund af forskellige login-koncepter i Oracle og MySQL.
Det svarer til sqlplus / as sysdba-forbindelse er "mysql"-terminalkommando med et flag -uroot. I MySQL-verdenen kaldes superbrugeren root. MySQL-databasebrugere (inklusive root) er defineret af navnet og værten, hvorfra den kan oprette forbindelse.
Oplysningerne om bruger og værter, hvorfra den kan oprette forbindelse, er gemt i mysql.user-tabellen. Med forbindelsesforsøget tjekker MySQL, om klientværten, brugernavnet og adgangskoden matcher rækken i metadatatabellen.
Dette er en lidt anden tilgang end i Oracle, hvor vi kun har et brugernavn og en adgangskode, men dem, der er fortrolige med Oracle Connection Manager, kan måske finde nogle ligheder.
Du vil ikke finde foruddefinerede TNS-poster som i Oracle. Normalt, for en adminforbindelse, har vi brug for bruger, adgangskode og -h værtsflag. Standardporten er 3306 (som 1521 i Oracle), men dette kan variere på forskellige opsætninger.
Som standard vil mange installationer have root-adgangsforbindelse fra enhver maskine ([email protected]'%') blokeret, så du skal logge ind på serveren, der hoster MySQL, typisk via ssh.
Indtast følgende:
mysql -u root
Når root-adgangskoden ikke er indstillet, er dette nok. Hvis adgangskoden er påkrævet, skal du tilføje flaget -p.
mysql -u root -p
Du er nu logget ind på mysql-klienten (svarende til sqlplus) og vil se en prompt, typisk 'mysql>'.
Kører MySQL?
Du kan bruge mysql-tjenestens opstartsscript eller mysqladmin-kommandoen til at finde ud af, om den kører. Så kan du bruge ps-kommandoen til at se, om mysql-processer er oppe og køre. Et andet alternativ kan være mysqladmin, som er et værktøj, der bruges til at udføre administrative handlinger.
mysqladmin -u root -p status
På Debian:
/etc/init.d/mysql status
Hvis du bruger RedHat eller Fedora, kan du bruge følgende script:
service mysqld status
Eller
/etc/init.d/mysqld status
Eller
systemctl status mysql.service
På MariaDB-instanser skal du kigge efter MariaDB-tjenestenavnet.
systemctl status mariadb
Hvad er der i denne database?
Ligesom i Oracle kan du forespørge på metadataobjekterne for at få information om databaseobjekter.
Det er almindeligt at bruge nogle genveje her, kommandoer, der hjælper dig med at liste objekter eller få DDL af objekterne.
show databases;
use database_name;
show tables;
show table status;
show index from table_name;
show create table table_name;
I lighed med Oracle kan du beskrive tabellen:
desc table_name;
Hvor er mine data gemt?
Der er ingen dedikeret intern lagring som ASM i MySQL. Alle datafiler placeres i de almindelige OS-monteringspunkter. Med en standardinstallation kan du finde dine data i:
/var/lib/mysql
Placeringen er baseret på den variable datadir.
[email protected]:~# cat /etc/mysql/my.cnf | grep datadir
datadir=/var/lib/mysql
Der vil du se en mappe for hver database.
Afhængigt af versionen og lagermotoren (ja, der er et par stykker her), kan databasens bibliotek indeholde filer i formatet *.frm, som definerer strukturen af hver tabel i databasen. For MyISAM-tabeller er dataene (*.MYD) og indekserne (*.MYI) også gemt i denne mappe.
InnoDB-tabeller gemmes i InnoDB-tablespaces. Hver af dem består af en eller flere filer, som ligner Oracle tablespaces. I en standardinstallation holdes alle InnoDB-data og indekser for alle databaser på en MySQL-server i ét tablespace, bestående af én fil:/var/lib/mysql/ibdata1. I de fleste opsætninger administrerer du ikke tablespaces som i Oracle. Den bedste praksis er at beholde dem med autoextend aktiveret og maksimal størrelse ubegrænset.
[email protected]:~# cat /etc/mysql/my.cnf | grep innodb-data-file-path
innodb-data-file-path = ibdata1:100M:autoextend
InnoDB har logfiler, som svarer til Oracle-redo-logfiler, hvilket muliggør automatisk gendannelse af nedbrud. Som standard er der to logfiler:/var/lib/mysql/ib_logfile0 og /var/lib/mysql/ib_logfile1. Fortryd-data opbevares i tablespace-filen.
[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
Hvor er metadataoplysningerne?
Der er ingen dba_*, user_*, all_* type visninger, men MySQL har interne metadatavisninger.
Information_schema er defineret i SQL 2003-standarden og implementeres af andre større databaser, f.eks. SQL Server, PostgreSQL.
Siden MySQL 5.0 har informationsskema-databasen været tilgængelig, der indeholder dataordbogsoplysninger. Oplysningerne blev faktisk gemt i de eksterne FRM-filer. Endelig, efter mange år er .frm-filer væk i version 8.0. Metadataene er stadig synlige i informationsskema-databasen, men bruger InnoDB-lagringsmotoren.
For at se alle faktiske visninger indeholdt i dataordbogen i mysql-klienten skal du skifte til informationsskemadatabasen:
use information_schema;
show tables;
Du kan finde yderligere information i MySQL-databasen, som indeholder information om db, hændelse (MySQL-job), plugins, replikering, database, brugere osv.
Antallet af visninger afhænger af version og leverandør.
Vælg * fra v$session
Oracles select * fra v$session er repræsenteret her med kommandoen SHOW PROCESSLIST, som viser listen over tråde.
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)
Den er baseret på oplysninger, der er gemt i informationsskema.proceslistevisningen. Visningen kræver at have PROCESS-privilegiet. Det kan også hjælpe dig med at kontrollere, om du løber tør for det maksimale antal processer.
Hvor er en advarselslog?
Fejlloggen kan findes i my.cnf eller via kommandoen 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)
Hvor er listen over brugere og deres tilladelser?
Oplysningerne om brugere gemmes i mysql.user-tabellen, mens bevillingerne gemmes flere steder, herunder mysql.user, mysql.tables_priv,
MySQL brugeradgang er defineret i:
mysql.columns_priv, mysql.tables_priv, mysql.db,mysql.user
Den foretrukne måde at liste bevillinger på er at bruge pt-grants, værktøjet fra Percona toolkit (et must-have for hver MySQL DBA).
pt-show-grants --host localhost --user root --ask-pass
Alternativt kan du bruge følgende forespørgsel (oprettet af 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;
Sådan opretter du en mysql-bruger
'Opret bruger'-proceduren ligner Oracle. Det enkleste eksempel kunne være:
CREATE user 'username'@'hostname' identified by 'password';
GRANT privilege_name on *.* TO 'username'@'hostname';
Muligheden for at tildele og oprette på én linje med:
GRANT privilege_name ON *.* TO 'username'@'hostname' identified by 'password';
er blevet fjernet i MySQL 8.0.
Hvordan starter og stopper jeg MySQL?
Du kan stoppe og starte MySQL med tjenesten.
Den faktiske kommando afhænger af Linux-distributionen og tjenestenavnet.
Nedenfor kan du finde et eksempel med tjenestenavnet 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
Hvor er MySQL-serverkonfigurationsdataene?
Konfigurationen er gemt i filen my.cnf.
Indtil version 8.0 krævede enhver dynamisk indstillingsændring, der skulle forblive efter en genstart, en manuel opdatering af my.cnf-filen. I lighed med Oracles scope=both kan du ændre værdier ved at bruge den vedvarende indstilling.
mysql> SET PERSIST max_connections = 1000;
mysql> SET @@PERSIST.max_connections = 1000;
For ældre versioner, brug:
mysql> SET GLOBAL max_connections = 1000;
$ vi /etc/mysql/my.cnf
SET GLOBAL max_connections = 1000;
Hvordan sikkerhedskopierer jeg MySQL?
Der er to måder at udføre en mysql backup på.
Til mindre databaser eller mindre selektive sikkerhedskopier kan du bruge kommandoen mysqldump.
Database backup med mysqldump (logisk backup):
mysqldump -uuser -p --databases db_name --routines --events --single-transaction | gzip > db_name_backup.sql.gz
xtrabackup, mariabackup (hot binær backup)
Den foretrukne metode er at bruge xtrabackup eller mariabackup, eksterne værktøjer til at køre hot binære backups.
Oracle tilbyder hot binær backup i den betalte version kaldet MySQL Enterprise Edition.
mariabackup --user=root --password=PASSWORD --backup --target-dir=/u01/backups/
Stream backup til anden server
Start en lytter på den eksterne server på den foretrukne port (i dette eksempel 1984)
nc -l 1984 | pigz -cd - | pv | xbstream -x -C /u01/backups
Kør backup og overfør til ekstern vært
innobackupex --user=root --password=PASSWORD --stream=xbstream /var/tmp | pigz | pv | nc external_host.com 1984
Kopiér brugertilladelse
Det er ofte nødvendigt at kopiere brugertilladelser og overføre dem til de andre servere.
Den anbefalede måde at gøre dette på er at bruge pt-show-grants.
pt-show-grants > /u01/backups
Hvordan gendanner jeg MySQL?
Gendannelse af logisk sikkerhedskopiering
MySQLdump opretter SQL-filen, som kan udføres med kildekommandoen.
Brug kommandoen tee for at beholde logfilen for udførelsen.
mysql> tee dump.log
mysql> source mysqldump.sql
Gendannelse af binær sikkerhedskopiering (xtrabackup/mariabackup)
For at gendanne MySQL fra den binære sikkerhedskopi skal du først gendanne filerne og derefter anvende logfilerne.
Du kan sammenligne denne proces for at gendanne og gendanne i Oracle.
xtrabackup --copy-back --target-dir=/var/lib/data
innobackupex --apply-log --use-memory=[values in MB or GB] /var/lib/data
Forhåbentlig giver disse tips et godt overblik over, hvordan man udfører grundlæggende administrative opgaver.