MariaDB 강좌 / 백업을 별도 데이터베이스에 복원하고 검증하기
백업 검증은 원본과 다른 빈 데이터베이스에 복원하고 구조·행·제약 조건·업무 합계를 대조하는 과정입니다. 덤프 안의 DB 전환·삭제 문장을 확인하고 오류에서 멈춘 뒤 원인을 해결해야 원본이나 다른 데이터를 잘못 덮어쓰는 일을 줄일 수 있습니다.
다른 DB 이름만 지정하면 안전하다고 가정하지 않기
덤프에 CREATE DATABASE·USE·완전 수식된 객체명이 들어 있으면 연결할 때 지정한 대상 DB와 다른 곳으로 작업할 수 있습니다. 복원 전에 파일을 검토하고 출처·버전·옵션을 확인하세요. 기본 덤프에는 DROP TABLE 같은 문장이 들어 있을 수 있으므로 기존 데이터가 있는 DB에 시험하지 않습니다.
| 검증 단계 | 확인 대상 | 판단 기준 |
|---|---|---|
| 파일 검토 | CREATE DATABASE·USE·DROP·DEFINER | 대상 밖 작업 여부 |
| 빈 대상 준비 | 실제 서버·DB 이름·권한 | 원본과 분리 |
| 복원 실행 | 첫 오류·종료 코드 | 부분 성공과 전체 성공 구분 |
| 검증 | 객체·행·키·업무 값 | 원본 기준과 일치 |
독립 실행용 원본과 덤프 준비하기
이 글은 restore47_source와 restore47_target이라는 새 이름을 사용합니다. 기존 이름이 없는지 관리자가 확인하고 아래 전체 데이터를 준비합니다. 앞 글의 백업을 사용하는 경우에는 그 파일 안의 테이블명·원본 기준값으로 검증 쿼리를 바꿔야 합니다. 두 실습 파일을 섞지 않습니다.
CREATE DATABASE restore47_source CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci; USE restore47_source; CREATE TABLE c47_customers ( customer_id INT NOT NULL PRIMARY KEY, customer_name VARCHAR(50) NOT NULL, city VARCHAR(30) NOT NULL ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; CREATE TABLE c47_products ( product_id INT NOT NULL PRIMARY KEY, product_name VARCHAR(100) NOT NULL, category VARCHAR(30) NOT NULL, price DECIMAL(10,2) NOT NULL CHECK (price >= 0), stock INT NOT NULL CHECK (stock >= 0) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; CREATE TABLE c47_orders ( order_id INT NOT NULL PRIMARY KEY, customer_id INT NOT NULL, ordered_at DATETIME NOT NULL, status VARCHAR(20) NOT NULL, shipping_fee DECIMAL(10,2) NOT NULL DEFAULT 1000, CONSTRAINT fk_c47_order_customer FOREIGN KEY (customer_id) REFERENCES c47_customers(customer_id) ON DELETE RESTRICT ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; CREATE TABLE c47_items ( order_id INT NOT NULL, product_id INT NOT NULL, quantity INT NOT NULL CHECK (quantity > 0), unit_price DECIMAL(10,2) NOT NULL CHECK (unit_price >= 0), PRIMARY KEY (order_id, product_id), CONSTRAINT fk_c47_item_order FOREIGN KEY (order_id) REFERENCES c47_orders(order_id) ON DELETE RESTRICT, CONSTRAINT fk_c47_item_product FOREIGN KEY (product_id) REFERENCES c47_products(product_id) ON DELETE RESTRICT ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; INSERT INTO c47_customers VALUES (1,'김민수','서울'),(2,'이서연','부산'), (3,'박지우','서울'),(4,'최하늘','대전'); INSERT INTO c47_products VALUES (1,'노트','문구',3500,20),(2,'볼펜','문구',1500,50), (3,'머그컵','생활',8000,12),(4,'스탠드','생활',25000,5); INSERT INTO c47_orders (order_id,customer_id,ordered_at,status,shipping_fee) VALUES (101,1,'2026-01-10 10:00:00','paid',1000), (102,1,'2026-01-20 11:00:00','paid',1000), (103,2,'2026-02-05 12:00:00','paid',1000), (104,3,'2026-02-10 13:00:00','canceled',1000); INSERT INTO c47_items VALUES (101,1,2,3500),(101,2,3,1500),(102,3,1,8000), (103,1,1,3500),(103,3,2,8000),(104,2,1,1500);
course_user에 해당 실습 DB들의 권한을 별도로 부여한 뒤 새 파일로 덤프합니다. 이 권한은 실제 운영 DB의 일괄 권한 부여를 뜻하지 않습니다.
GRANT ALL PRIVILEGES ON restore47_source.* TO 'course_user'@'127.0.0.1'; CREATE DATABASE restore47_target CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci; GRANT ALL PRIVILEGES ON restore47_target.* TO 'course_user'@'127.0.0.1';
mariadb-dump --protocol=tcp --host=127.0.0.1 --port=3306 --user=course_user --password --default-character-set=utf8mb4 --single-transaction --quick --skip-lock-tables --result-file=C:/mariadb-lab/restore47-source.sql restore47_source
빈 대상을 다시 확인하고 같은 버전 도구로 복원하기
터미널에서 대상 DB로 연결하고 VERSION·DATABASE를 확인합니다. SHOW TABLES가 비어 있는지 확인한 다음 SOURCE로 파일을 읽습니다. SQL 파일은 내용이 신뢰되는지 먼저 검토하고 실행하며, 다른 사용자 파일을 검토 없이 가져오지 않습니다.
mariadb --protocol=tcp --host=127.0.0.1 --port=3306 --user=course_user --password --default-character-set=utf8mb4 restore47_target
SELECT VERSION(),DATABASE(); SHOW TABLES; SOURCE C:/mariadb-lab/restore47-source.sql;
최근 mariadb-dump는 파일 앞에 sandbox 관련 지시문을 넣을 수 있어 이를 지원하지 않는 구형 MariaDB·MySQL 클라이언트에서 오류가 날 수 있습니다. 지시문을 무조건 삭제하는 대신 호환되는 MariaDB 도구 조합을 확인합니다. 덤프 파일과 클라이언트 호환성 안내를 참고하세요.
테이블 수·행 수·관계·업무 금액 비교하기
SELECT TABLE_NAME,TABLE_TYPE FROM information_schema.TABLES WHERE TABLE_SCHEMA='restore47_target' ORDER BY TABLE_NAME; SELECT (SELECT COUNT(*) FROM restore47_target.c47_customers) AS customers, (SELECT COUNT(*) FROM restore47_target.c47_products) AS products, (SELECT COUNT(*) FROM restore47_target.c47_orders) AS orders_count, (SELECT COUNT(*) FROM restore47_target.c47_items) AS detail_rows; SELECT SUM(i.quantity*i.unit_price) AS paid_goods FROM restore47_target.c47_orders o JOIN restore47_target.c47_items i ON i.order_id=o.order_id WHERE o.status='paid'; SHOW CREATE TABLE restore47_target.c47_items;
기본 테이블 네 개, 고객 4·상품 4·주문 4·상세 6, paid 상품 금액 39000.00이 예상됩니다. SHOW CREATE TABLE에서 기본키·외래키·수량·단가의 제약도 확인합니다. 행 수가 같아도 행 내용이 다를 수 있으므로 기본키별 원본 값과 핵심 집계, 필요한 업무 조회를 함께 비교해야 합니다.
뷰·루틴·트리거·이벤트가 있는 실제 시스템은 객체 수와 실행 동작도 검증합니다. 덤프가 계정·권한·서버 설정까지 자동 복구한다고 가정하지 않고 필요한 정의자·호출 계정의 권한을 따로 확인합니다.
오류에서 멈추고 부분 복원 상태를 구분하기
문법·권한·정의자·문자 집합 오류가 발생하면 이미 일부 객체가 생성되었을 수 있습니다. --force로 계속 진행한 결과를 정상 복원으로 보고하지 않습니다. 오류와 생성된 객체를 기록하고 원인을 해결한 뒤 새로운 빈 대상에서 다시 검증하는 편이 명확합니다.
외래키 오류를 없애려고 임의로 검사 설정만 끄지 않습니다. 파일이 원래 넣고 복원하는 설정을 확인하고 종료 시 연결 상태도 확인합니다. DDL·복원 전체가 하나의 ROLLBACK으로 취소될 것이라고 생각하면 안 됩니다. 운영 복구의 전환·접속 차단·후속 쓰기 방지는 별도 승인된 절차가 필요합니다.
검증 증거와 보관 필요성을 확인하기
원본 덤프의 해시·도구 버전·대상 서버·복원 시간·검증 쿼리와 결과를 기록합니다. 모든 검증이 끝나기 전에 원본 DB나 백업을 지우지 않습니다. 실습 후 DB를 정리하려면 각 이름이 이 글에서 만든 폐기 가능한 대상인지 다시 확인하고 필요한 자료를 별도로 보관한 뒤 관리자 권한으로 처리합니다. 이 글은 자동 DROP DATABASE를 실행하지 않습니다.










