-
MySQL mysqldump 알아보기Database 2023. 5. 18. 06:21728x90반응형
- 목차
소개.
mysqldump 는 MySQL 의 데이터 상태를 백업할 수 있는 MySQL 툴입니다.
특정 시점의 MySQL 의 데이터 상태를 스냅샷이라고도 하는데요.
mysqldump 를 통해서 특정 시점의 스냅샷을 생성할 수 있습니다.
mysqldump 는 Logical Backup 이라고 불립니다.
이와 반대되는 backup 방식은 Physical Backup 입니다.
MySQL 의 On-Disk 요소인 Tablespace 와 Redo Log 등을 고려하는
Physical Backup 과 달리 Logical Backup 은 단순히 dump 시점의 데이터 상태만들 고려합니다.
즉, Logical Backup 은 Table 에 Lock 을 걸어 현재 시점의 데이터들을 전부 조회하고 조회된 데이터들을 Write 하는 sql 파일을 생성합니다.
이 상황에서 In-Memory <-> On-Disk 의 동기화가 되지 않을 수도 있습니다.
따라서 Logical Backup 은 필연적으로
- "LOCK table write"
- "select * from table"
두 쿼리가 사용됩니다.
How to User mysqldump?
mysqldump 의 사용법을 설명해보록 하겠습니다.
Table Level Dump.
Table Level Dump 는 하나의 Table 을 dump 하는 방식입니다.
먼저 docker 를 활용하여 MySQL 컨테이너를 생성합니다.
< MySQL 실행 >docker run -d -it --name mysql --platform linux/amd64 -e MYSQL_ROOT_PASSWORD=1234 mysql:8.0.23
아래의 코드예시는 test_db 라는 데이터베이스와 test_table 이라는 테이블을 생성하는 코드흐름입니다.
< 테이블 생성 >// MySQL Docker Container 로 진입 docker exec -it mysql /bin/sh // MySQL 로 진입 mysql -u root -p 1234 // 테이블을 생성 create database test_db; use test_db; create table test_table( id int not null auto_increment primary key, test_col varchar(32) );
좀더 세부적인 실험을 위하여 insert query 하나와 update query 하나를 실행합니다.
결과적으로 test_table 이라는 테이블은 test_col 이 "test2" 인 Row 하나만이 존재합니다.
< 1개의 insert 와 1개의 update >mysql> insert into test_table(test_col) values('test1'); Query OK, 1 row affected (0.02 sec) Rows matched: 1 Changed: 1 Warnings: 0 mysql> update test_table set test_col = 'test2' where id = 1; Query OK, 1 row affected (0.02 sec) Rows matched: 1 Changed: 1 Warnings: 0
mysqldump 를 활용하여 test_table 을 dump 합니다.
< test_table 의 backup >mysqldump -u root -p test_db test_table > /tmp/backup.sql
mysqldump 를 사용하여 하나의 sql 파일이 생성됩니다.
backup.sql 이라고 파일명을 지었구요.
backup.sql 파일은 mysqldump 를 실행하는 시점의 test_table 의 상태를 복원할 수 있는 DDL & DML Query 로 구성됩니다.
아래의 코드들은 backup.sql 의 내용입니다.
test_table 테이블을 생성하는 DDL 쿼리와
test_table 의 Row 를 생성하는 DML 쿼리로 구성됩니다.
그리고 Table Lock 을 적용하는 부분도 있죠.
< dump 결과 확인 >cat /tmp/backup.sql
-- MySQL dump 10.13 Distrib 8.0.23, for Linux (x86_64) -- -- Host: localhost Database: test_db -- ------------------------------------------------------ -- Server version 8.0.23 /*!40101 SET @OLD_CHARACTER_SET_CLIENT=@@CHARACTER_SET_CLIENT */; /*!40101 SET @OLD_CHARACTER_SET_RESULTS=@@CHARACTER_SET_RESULTS */; /*!40101 SET @OLD_COLLATION_CONNECTION=@@COLLATION_CONNECTION */; /*!50503 SET NAMES utf8mb4 */; /*!40103 SET @OLD_TIME_ZONE=@@TIME_ZONE */; /*!40103 SET TIME_ZONE='+00:00' */; /*!40014 SET @OLD_UNIQUE_CHECKS=@@UNIQUE_CHECKS, UNIQUE_CHECKS=0 */; /*!40014 SET @OLD_FOREIGN_KEY_CHECKS=@@FOREIGN_KEY_CHECKS, FOREIGN_KEY_CHECKS=0 */; /*!40101 SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='NO_AUTO_VALUE_ON_ZERO' */; /*!40111 SET @OLD_SQL_NOTES=@@SQL_NOTES, SQL_NOTES=0 */; -- -- Table structure for table `test_table` -- DROP TABLE IF EXISTS `test_table`; /*!40101 SET @saved_cs_client = @@character_set_client */; /*!50503 SET character_set_client = utf8mb4 */; CREATE TABLE `test_table` ( `id` int NOT NULL AUTO_INCREMENT, `test_col` varchar(32) DEFAULT NULL, PRIMARY KEY (`id`) ) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci; /*!40101 SET character_set_client = @saved_cs_client */; -- -- Dumping data for table `test_table` -- LOCK TABLES `test_table` WRITE; /*!40000 ALTER TABLE `test_table` DISABLE KEYS */; INSERT INTO `test_table` VALUES (1,'test2'); /*!40000 ALTER TABLE `test_table` ENABLE KEYS */; UNLOCK TABLES; /*!40103 SET TIME_ZONE=@OLD_TIME_ZONE */; /*!40101 SET SQL_MODE=@OLD_SQL_MODE */; /*!40014 SET FOREIGN_KEY_CHECKS=@OLD_FOREIGN_KEY_CHECKS */; /*!40014 SET UNIQUE_CHECKS=@OLD_UNIQUE_CHECKS */; /*!40101 SET CHARACTER_SET_CLIENT=@OLD_CHARACTER_SET_CLIENT */; /*!40101 SET CHARACTER_SET_RESULTS=@OLD_CHARACTER_SET_RESULTS */; /*!40101 SET COLLATION_CONNECTION=@OLD_COLLATION_CONNECTION */; /*!40111 SET SQL_NOTES=@OLD_SQL_NOTES */; -- Dump completed on 2023-10-22 5:51:18
주목할 점은
- LOCK TABLE `test_table` WRITE
- INSERT query
입니다.
dump 시에는 해당 table 에 WRITE LOCK 이 걸리므로 단순읽기를 제외한
shared lock, exclusive lock 이 걸린 Read Query 와 모든 Write Query 는 Wait 상태에 머물게 됩니다.
그리고 test_table 테이블은 Insert 쿼리와 Update 쿼리라는 변경 기록이 존재하지만,
mysqldump 의 backup.sql 에는 마지막 상태를 insert 하기 위한 쿼리만이 존재합니다.
INSERT INTO test_table(name) VALUES('test1'); UDPATE test_table SET name = 'test2' WHERE id = 1'; 아래 상태로 변경. INSERT INTO test_table(name) VALUES('test2');
Database Level Dump.
데이터베이스 레벨의 mysqldump 를 테스트하기 위해서
하나의 테이블을 더 생성하도록 하겠습니다.
< 추가적인 테이블 생성 >create table test_table2( id int not null auto_increment primary key, test_col varchar(32) ); insert into test_table2(test_col) values('value1'), ('value2'), ('value3');
데이터베이스 레벨의 mysqldump 는 데이터베이스 이름만 사용합니다.
< Database Level mysqldump >mysqldump -u root -p test_db > /tmp/backup.sql
backup.sql 의 내용은 테이블 레벨, 데이터베이스 레벨과 상관없이 유사합니다.
데이터베이스가 관리하는 모든 테이블의 DDL 과 DML 쿼리들이 기록됩니다.
< backup.sql 내용 >cat /tmp/backup.sql
-- MySQL dump 10.13 Distrib 8.0.23, for Linux (x86_64) -- -- Host: localhost Database: test_db -- ------------------------------------------------------ -- Server version 8.0.23 /*!40101 SET @OLD_CHARACTER_SET_CLIENT=@@CHARACTER_SET_CLIENT */; /*!40101 SET @OLD_CHARACTER_SET_RESULTS=@@CHARACTER_SET_RESULTS */; /*!40101 SET @OLD_COLLATION_CONNECTION=@@COLLATION_CONNECTION */; /*!50503 SET NAMES utf8mb4 */; /*!40103 SET @OLD_TIME_ZONE=@@TIME_ZONE */; /*!40103 SET TIME_ZONE='+00:00' */; /*!40014 SET @OLD_UNIQUE_CHECKS=@@UNIQUE_CHECKS, UNIQUE_CHECKS=0 */; /*!40014 SET @OLD_FOREIGN_KEY_CHECKS=@@FOREIGN_KEY_CHECKS, FOREIGN_KEY_CHECKS=0 */; /*!40101 SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='NO_AUTO_VALUE_ON_ZERO' */; /*!40111 SET @OLD_SQL_NOTES=@@SQL_NOTES, SQL_NOTES=0 */; -- -- Table structure for table `test_table` -- DROP TABLE IF EXISTS `test_table`; /*!40101 SET @saved_cs_client = @@character_set_client */; /*!50503 SET character_set_client = utf8mb4 */; CREATE TABLE `test_table` ( `id` int NOT NULL AUTO_INCREMENT, `test_col` varchar(32) DEFAULT NULL, PRIMARY KEY (`id`) ) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci; /*!40101 SET character_set_client = @saved_cs_client */; -- -- Dumping data for table `test_table` -- LOCK TABLES `test_table` WRITE; /*!40000 ALTER TABLE `test_table` DISABLE KEYS */; INSERT INTO `test_table` VALUES (1,'test2'); /*!40000 ALTER TABLE `test_table` ENABLE KEYS */; UNLOCK TABLES; -- -- Table structure for table `test_table2` -- DROP TABLE IF EXISTS `test_table2`; /*!40101 SET @saved_cs_client = @@character_set_client */; /*!50503 SET character_set_client = utf8mb4 */; CREATE TABLE `test_table2` ( `id` int NOT NULL AUTO_INCREMENT, `test_col` varchar(32) DEFAULT NULL, PRIMARY KEY (`id`) ) ENGINE=InnoDB AUTO_INCREMENT=4 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci; /*!40101 SET character_set_client = @saved_cs_client */; -- -- Dumping data for table `test_table2` -- LOCK TABLES `test_table2` WRITE; /*!40000 ALTER TABLE `test_table2` DISABLE KEYS */; INSERT INTO `test_table2` VALUES (1,'value1'),(2,'value2'),(3,'value3'); /*!40000 ALTER TABLE `test_table2` ENABLE KEYS */; UNLOCK TABLES; /*!40103 SET TIME_ZONE=@OLD_TIME_ZONE */; /*!40101 SET SQL_MODE=@OLD_SQL_MODE */; /*!40014 SET FOREIGN_KEY_CHECKS=@OLD_FOREIGN_KEY_CHECKS */; /*!40014 SET UNIQUE_CHECKS=@OLD_UNIQUE_CHECKS */; /*!40101 SET CHARACTER_SET_CLIENT=@OLD_CHARACTER_SET_CLIENT */; /*!40101 SET CHARACTER_SET_RESULTS=@OLD_CHARACTER_SET_RESULTS */; /*!40101 SET COLLATION_CONNECTION=@OLD_COLLATION_CONNECTION */; /*!40111 SET SQL_NOTES=@OLD_SQL_NOTES */; -- Dump completed on 2023-10-22 6:05:36
Heavy 한 테이블의 backup.
Heavy 한 테이블을 만들어보겠습니다.
25 개의 column 을 가지며, 1백만개의 row 를 가지는 테이블을 backup 하는 테스트입니다.
< test_table 테이블 >create table test_table ( a int not null auto_increment primary key, b varchar(256) default (UUID()), c varchar(256) default (UUID()), d varchar(256) default (UUID()), e varchar(256) default (UUID()), f varchar(256) default (UUID()), g varchar(256) default (UUID()), h varchar(256) default (UUID()), i varchar(256) default (UUID()), j varchar(256) default (UUID()), k varchar(256) default (UUID()), l varchar(256) default (UUID()), m varchar(256) default (UUID()), n varchar(256) default (UUID()), o varchar(256) default (UUID()), p varchar(256) default (UUID()), q varchar(256) default (UUID()), r varchar(256) default (UUID()), s varchar(256) default (UUID()), t varchar(256) default (UUID()), u varchar(256) default (UUID()), v varchar(256) default (UUID()), x varchar(256) default (UUID()), y varchar(256) default (UUID()), z varchar(256) default (UUID()) );
< 1백만개 row insert procedure >DELIMITER $$ DROP PROCEDURE IF EXISTS insert_bulk_data; CREATE PROCEDURE insert_bulk_data () BEGIN DECLARE X INT; SET X=1; WHILE X <= 1000000 DO INSERT INTO test_db.test_table() values(); SET X=X+1; END WHILE; END$$ DELIMITER ; CALL insert_bulk_data(); SELECT count(*) from test_table;
1. mysqldump 하는 시간동안에 read query 가 동작하는가?
mysqldump 동안에는 단순한 select 쿼리와 share lock 을 동작합니다.
< mysqldump 동안 가능한 쿼리 >select a from test_table order by a desc limit 1; select a from test_table order by a desc limit 1 for share;
반면, DML query 들과 write lock 을 동작하지 않습니다.
< mysqldump 동안 불가능한 쿼리 >select a from test_table order by a desc limit 1 for update; insert into test_table values(); update test_table set b = 'test' where a != 'test'; delete from test_table limit 1;
2. insert query 가 끝난 직후 mysqldump 하면 완벽하게 backup 이 될까 ?
mysqldump 를 통해서 backup.sql 파일을 만들 때에
"select * from table" 과 같은 쿼리문을 통해서 데이터들을 조회합니다.
이 과정에서 데이터들이 In-Memory, On-Disk 의 상태를 상관하지 않고,
현재의 데이터 상태를 조회합니다.
그래서 backup.sql 의 결과는 실제 MySQL 의 데이터 스냅샷과 동일합니다.
< 547677 개의 row 를 backup 한 이후의 count 조회 >
select count(*) as count from test_table; +--------+ | count | +--------+ | 547677 | +--------+
Backup sql 적용하기.
backup.sql 파일을 적용하는 것은 간단합니다.
mysql 내부에서 source 명령어를 사용하면 됩니다.
mysql -u root -p use test_db; source /tmp/back.up;
< 실행 결과 >Query OK, 1106 rows affected (0.19 sec) Records: 1106 Duplicates: 0 Warnings: 0 Query OK, 1106 rows affected (0.19 sec) Records: 1106 Duplicates: 0 Warnings: 0 Query OK, 1106 rows affected (0.18 sec) Records: 1106 Duplicates: 0 Warnings: 0 Query OK, 1106 rows affected (0.20 sec) Records: 1106 Duplicates: 0 Warnings: 0 Query OK, 1106 rows affected (0.19 sec) Records: 1106 Duplicates: 0 Warnings: 0
반응형'Database' 카테고리의 다른 글
MySQL Replication (0) 2023.09.11 MySQL my.cnf (0) 2023.09.11 Mysql Procedure (0) 2023.05.15 MySQL Tablespace 알아보기 (0) 2023.05.12 MySQL ACID Compliant (0) 2023.05.08