Open source databáze se rychle stávají mainstreamem, takže migrace z proprietárních enginů na open source enginy je nyní jakýmsi trendem v oboru. Znamená to také, že my správci databází často musíme spravovat více databázových backendů.
V několika minulých příspěvcích na blogu jsme se s kolegou Paulem Namuagem zabývali několika aspekty migrace z Oracle na Percona, MariaDB a MySQL. Zřejmým cílem migrace je zprovoznit vaši aplikaci efektivněji v novém databázovém prostředí, je však zásadní zajistit, aby byli zaměstnanci připraveni ji podporovat.
Tento blog se zabývá základními operacemi MySQL s odkazem na podobné úkoly, které byste denně prováděli v prostředí Oracle. Poskytuje vám hluboký ponor do různých témat, abyste ušetřili čas, protože se můžete ztotožnit se znalostmi Oracle, které jste si již za ta léta vybudovali.
Budeme také mluvit o externích nástrojích příkazového řádku, které ve výchozí instalaci MySQL chybí, ale jsou potřebné k efektivnímu provádění každodenních operací. Verze s otevřeným zdrojovým kódem není dodávána s ekvivalentem například Oracle Cloud Control, takže pokud hledáte něco podobného, podívejte se na ClusterControl.
V tomto blogu předpokládáme, že máte lepší znalosti Oracle než MySQL, a proto byste rádi znali vzájemný vztah mezi těmito dvěma. Příklady jsou založeny na platformě Linux, nicméně ve správě MySQL na Windows můžete najít mnoho podobností.
Jak se připojím k MySQL?
Začněme naši cestu velmi (zdánlivě) základním úkolem. Ve skutečnosti se jedná o druh úkolu, který může způsobit určitý zmatek kvůli odlišným konceptům přihlašování v Oracle a MySQL.
Ekvivalentem sqlplus / jako připojení sysdba je terminálový příkaz „mysql“ s příznakem -uroot. Ve světě MySQL se superuživatel nazývá root. Uživatelé databáze MySQL (včetně root) jsou definováni jménem a hostitelem, odkud se mohou připojit.
Informace o uživateli a hostitelích, odkud se může připojit, jsou uloženy v tabulce mysql.user. Při pokusu o připojení MySQL zkontroluje, zda klientský hostitel, uživatelské jméno a heslo odpovídají řádku v tabulce metadat.
Je to trochu jiný přístup než v Oracle, kde máme pouze uživatelské jméno a heslo, ale ti, kteří znají Oracle Connection Manager, mohou najít určité podobnosti.
Nenajdete zde předdefinované položky TNS jako v Oracle. Obvykle pro připojení správce potřebujeme uživatele, heslo a příznak hostitele -h. Výchozí port je 3306 (jako 1521 v Oracle), ale to se může lišit v různých nastaveních.
Ve výchozím nastavení bude mít mnoho instalací zablokované připojení root z jakéhokoli počítače ([email protected]’%’), takže se musíte přihlásit k serveru hostujícímu MySQL, obvykle přes ssh.
Zadejte následující:
mysql -u root
Pokud není nastaveno heslo root, stačí to. Pokud je vyžadováno heslo, měli byste přidat parametr -p.
mysql -u root -p
Nyní jste přihlášeni ke klientovi mysql (ekvivalent sqlplus) a zobrazí se výzva, obvykle 'mysql>'.
Je MySQL v provozu?
Chcete-li zjistit, zda je spuštěna, můžete použít spouštěcí skript služby mysql nebo příkaz mysqladmin. Poté můžete pomocí příkazu ps zjistit, zda jsou procesy mysql v provozu. Další alternativou může být mysqladmin, což je nástroj, který se používá k provádění administrativních operací.
mysqladmin -u root -p status
V Debianu:
/etc/init.d/mysql status
Pokud používáte RedHat nebo Fedoru, můžete použít následující skript:
service mysqld status
Nebo
/etc/init.d/mysqld status
Nebo
systemctl status mysql.service
V instancích MariaDB byste měli hledat název služby MariaDB.
systemctl status mariadb
Co je v této databázi?
Podobně jako v Oracle můžete dotazovat na objekty metadat a získat informace o databázových objektech.
Je běžné zde používat některé zkratky, příkazy, které vám pomohou vypsat objekty nebo získat DDL objektů.
show databases;
use database_name;
show tables;
show table status;
show index from table_name;
show create table table_name;
Podobně jako u Oracle můžete tabulku popsat:
desc table_name;
Kde jsou moje data uložena?
V MySQL neexistuje žádné vyhrazené interní úložiště jako ASM. Všechny datové soubory jsou umístěny v běžných přípojných bodech OS. Při výchozí instalaci můžete svá data najít v:
/var/lib/mysql
Umístění je založeno na proměnné datadir.
[email protected]:~# cat /etc/mysql/my.cnf | grep datadir
datadir=/var/lib/mysql
Uvidíte zde adresář pro každou databázi.
V závislosti na verzi a úložišti (ano, je jich zde několik) může adresář databáze obsahovat soubory ve formátu *.frm, které definují strukturu každé tabulky v databázi. U tabulek MyISAM jsou data (*.MYD) a indexy (*.MYI) také uloženy v tomto adresáři.
Tabulky InnoDB jsou uloženy v tabulkových prostorech InnoDB. Každý z nich se skládá z jednoho nebo více souborů, které jsou podobné tabulkovým prostorům Oracle. Ve výchozí instalaci jsou všechna data a indexy InnoDB pro všechny databáze na serveru MySQL uloženy v jednom tabulkovém prostoru, který se skládá z jednoho souboru:/var/lib/mysql/ibdata1. Ve většině nastavení nespravujete tabulkové prostory jako v Oracle. Nejlepším postupem je ponechat je se zapnutým automatickým rozšířením a maximální velikostí neomezenou.
[email protected]:~# cat /etc/mysql/my.cnf | grep innodb-data-file-path
innodb-data-file-path = ibdata1:100M:autoextend
InnoDB má log soubory, které jsou ekvivalentem Oracle redo logs, což umožňuje automatické zotavení po havárii. Ve výchozím nastavení existují dva soubory protokolu:/var/lib/mysql/ib_logfile0 a /var/lib/mysql/ib_logfile1. Data zpět jsou uložena v souboru tabulkového prostoru.
[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
Kde jsou informace o metadatech?
Neexistují žádné typy zobrazení dba_*, user_*, all_*, ale MySQL má interní zobrazení metadat.
Information_schema je definováno ve standardu SQL 2003 a je implementováno dalšími významnými databázemi, např. SQL Server, PostgreSQL.
Od MySQL 5.0 je k dispozici databáze information_schema obsahující informace z datového slovníku. Informace byly ve skutečnosti uloženy v externích souborech FRM. Konečně, po mnoha letech jsou soubory .frm pryč ve verzi 8.0. Metadata jsou stále viditelná v databázi information_schema, ale používají úložiště InnoDB.
Chcete-li vidět všechny skutečné pohledy obsažené v datovém slovníku v rámci klienta mysql, přepněte do databáze information_schema:
use information_schema;
show tables;
Další informace můžete najít v databázi MySQL, která obsahuje informace o db, události (úlohy MySQL), pluginech, replikaci, databázi, uživatelích atd.
Počet zobrazení závisí na verzi a dodavateli.
Vyberte * z v$session
Oracle select * from v$session je zde reprezentován příkazem SHOW PROCESSLIST, který zobrazí seznam vláken.
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)
Je založen na informacích uložených v zobrazení information_schema.processlist. Pohled vyžaduje oprávnění PROCESS. Může vám také pomoci zkontrolovat, zda vám nedochází maximální počet procesů.
Kde je protokol výstrah?
Protokol chyb lze nalézt v my.cnf nebo pomocí příkazu 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)
Kde je seznam uživatelů a jejich oprávnění?
Informace o uživatelích jsou uloženy v tabulce mysql.user, zatímco granty jsou uloženy na několika místech, včetně mysql.user, mysql.tables_priv,
Uživatelský přístup k MySQL je definován v:
mysql.columns_priv, mysql.tables_priv, mysql.db,mysql.user
Nejvhodnějším způsobem, jak vypsat granty, je použít pt-grants, nástroj z Percona toolkit (nezbytný pro každý MySQL DBA).
pt-show-grants --host localhost --user root --ask-pass
Případně můžete použít následující dotaz (vytvořil 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;
Jak vytvořit uživatele mysql
Postup ‚vytvoření uživatele‘ je podobný jako u Oracle. Nejjednodušší příklad by mohl být:
CREATE user 'username'@'hostname' identified by 'password';
GRANT privilege_name on *.* TO 'username'@'hostname';
Možnost udělit a vytvořit v jednom řádku pomocí:
GRANT privilege_name ON *.* TO 'username'@'hostname' identified by 'password';
byl odstraněn v MySQL 8.0.
Jak spustím a zastavím MySQL?
Pomocí této služby můžete zastavit a spustit MySQL.
Skutečný příkaz závisí na distribuci Linuxu a názvu služby.
Níže naleznete příklad s názvem služby 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
Kde jsou data konfigurace serveru MySQL?
Konfigurace je uložena v souboru my.cnf.
Do verze 8.0 vyžadovala jakákoli dynamická změna nastavení, která by měla zůstat po restartu, ruční aktualizaci souboru my.cnf. Podobně jako u Oracle scope=both můžete hodnoty změnit pomocí trvalé možnosti.
mysql> SET PERSIST max_connections = 1000;
mysql> SET @@PERSIST.max_connections = 1000;
Pro starší verze použijte:
mysql> SET GLOBAL max_connections = 1000;
$ vi /etc/mysql/my.cnf
SET GLOBAL max_connections = 1000;
Jak zálohuji MySQL?
Existují dva způsoby, jak provést zálohu mysql.
Pro menší databáze nebo menší selektivní zálohy můžete použít příkaz mysqldump.
Záloha databáze pomocí mysqldump (logická záloha):
mysqldump -uuser -p --databases db_name --routines --events --single-transaction | gzip > db_name_backup.sql.gz
xtrabackup, mariabackup (horká binární záloha)
Upřednostňovanou metodou je použití xtrabackup nebo mariabackup, externích nástrojů pro spouštění horkých binárních záloh.
Oracle nabízí horké binární zálohování v placené verzi s názvem MySQL Enterprise Edition.
mariabackup --user=root --password=PASSWORD --backup --target-dir=/u01/backups/
Streamujte zálohování na jiný server
Spusťte posluchač na externím serveru na preferovaném portu (v tomto příkladu 1984)
nc -l 1984 | pigz -cd - | pv | xbstream -x -C /u01/backups
Spusťte zálohování a přeneste na externí hostitel
innobackupex --user=root --password=PASSWORD --stream=xbstream /var/tmp | pigz | pv | nc external_host.com 1984
Kopírovat oprávnění uživatele
Často je potřeba zkopírovat uživatelská oprávnění a přenést je na jiné servery.
Doporučený způsob, jak toho dosáhnout, je použít pt-show-grants.
pt-show-grants > /u01/backups
Jak obnovím MySQL?
Obnovení logické zálohy
MySQLdump vytvoří soubor SQL, který lze spustit pomocí příkazu source.
Chcete-li zachovat soubor protokolu provádění, použijte příkaz tee.
mysql> tee dump.log
mysql> source mysqldump.sql
Obnovení binární zálohy (xtrabackup/mariabackup)
Chcete-li obnovit MySQL z binární zálohy, musíte nejprve obnovit soubory a poté použít soubory protokolu.
Tento proces můžete porovnat s obnovou a obnovou v Oracle.
xtrabackup --copy-back --target-dir=/var/lib/data
innobackupex --apply-log --use-memory=[values in MB or GB] /var/lib/data
Doufejme, že tyto tipy poskytují dobrý přehled o tom, jak provádět základní administrativní úkoly.