카테고리 : MySQL/기술노트

mysqldump 운영 기준: --single-transaction, --routines, --triggers, --events

mysqldump의 스냅샷 일관성 범위와 저장 프로그램 포함 기준을 설명하고, 실제 덤프·복원으로 데이터와 객체 누락 여부를 검증한다.

저자: MySQL 기술 노트 작성: 2026.09.24 약 12분 6,606자
다운로드

백업 명령이 정상 종료되었는데 복원한 애플리케이션에서 프로시저를 찾지 못하거나 정기 집계가 멈추는 경우가 있다. 반대로 테이블과 저장 프로그램이 모두 있어도 데이터가 서로 다른 시점의 상태라면 정상적인 복구라고 할 수 없다. mysqldump 운영 기준은 데이터의 시점 일관성, 복원할 객체의 범위, 복원 후 실행 권한과 부작용을 각각 정의하는 데서 시작한다.

이 글은 MySQL 8.0 이상과 8.4 LTS의 동작을 기준으로 설명한다. 예제는 폐기용 MySQL 8.0에서 실행한다. 네 가지 옵션만 암기하기보다, 어떤 복구 목표를 보장하고 무엇은 보장하지 못하는지 구분하는 것이 목적이다.

1. 네 가지 옵션은 서로 다른 문제를 해결한다

옵션 보장하려는 범위 운영상 주의점
--single-transaction 하나의 트랜잭션에서 읽는 InnoDB 행 데이터의 일관된 스냅샷 비트랜잭션 테이블과 동시 DDL까지 보호하지 않는다.
--routines 저장 프로시저와 저장 함수의 정의 기본값에 의존하면 빠진다. 정의를 읽는 권한과 복원 시 생성 권한이 필요하다.
--triggers 덤프 대상 테이블의 트리거 정의 기본적으로 켜져 있지만 운영 명령에는 의도를 명시한다.
--events Event Scheduler 이벤트의 정의 기본값에 의존하면 빠진다. 복원 직후 자동 실행 여부를 별도로 통제한다.

--routines--events는 명시적으로 추가한다. MySQL 8.0 이상에서 --all-databases만 지정했다고 저장 프로그램까지 모두 복구할 수 있다고 가정하면 안 된다. 트리거는 별도 스키마 전체 옵션이 아니라 덤프 대상 테이블에 연결된 객체다. 일부 테이블만 내보내면 제외한 테이블의 트리거도 백업 범위 밖이다.

뷰, 계정, 역할, 권한, 서버 설정, 플러그인, 외부 파일까지 이 네 옵션으로 포괄하는 것도 아니다. 특히 업무 스키마 덤프는 사용자와 권한 백업을 대신하지 않는다. 복구 대상 목록에는 데이터 객체와 보안·실행 환경을 구분해서 기록해야 한다.

2. --single-transaction이 만드는 일관성 경계

mysqldump는 데이터를 SQL 문장으로 직렬화하는 클라이언트다. 이 옵션을 사용하면 연결의 격리 수준을 REPEATABLE READ로 설정하고 일관된 읽기를 위한 트랜잭션을 시작한다. 이후 InnoDB 테이블을 차례로 읽더라도 같은 스냅샷을 기준으로 행 버전을 선택한다. 덤프가 끝날 때의 최신 데이터가 아니라 덤프 트랜잭션의 스냅샷 기준 데이터를 얻는다.

동시에 다른 연결이 행을 변경하고 커밋할 수 있다. InnoDB는 필요한 과거 행 버전을 undo로 재구성한다. 이 때문에 전체 덤프 시간 동안 쓰기를 막는 테이블 잠금은 피할 수 있지만, 오래 유지되는 Read View가 purge 진행을 늦추고 undo 이력을 오래 남길 수 있다. 덤프 파일을 느린 원격 저장소에 직접 쓰거나 네트워크가 정체되면 읽기 트랜잭션도 길어질 수 있다.

flowchart TD
    A[엔진·객체·권한 확인] --> B[대상 DDL 변경 중지]
    B --> C[InnoDB 일관된 스냅샷 시작]
    C --> D[테이블 행을 순차적으로 읽기]
    W[다른 연결의 DML과 커밋] --> U[이전 행 버전은 undo에 유지]
    U --> D
    D --> E[저장 프로그램 정의를 포함한 덤프 완료]
    E --> F[격리된 대상에 복원]
    F --> G[행·객체·실행 권한 검증]
    G --> H[이벤트와 업무 트래픽 허용]

2.1 잠금이 없다는 표현은 부정확하다

--single-transaction--lock-tables는 함께 사용할 성격의 옵션이 아니다. LOCK TABLES는 진행 중인 트랜잭션을 암묵적으로 커밋하기 때문이다. 옵션 파일이나 명령 뒤쪽에서 --lock-tables 또는 이를 포함하는 옵션 묶음을 다시 켜지 않는지 확인한다.

또한 SELECT도 메타데이터 잠금과 무관하지 않다. 대상 테이블에 대한 ALTER TABLE, CREATE TABLE, DROP TABLE, RENAME TABLE, TRUNCATE TABLE을 덤프와 동시에 수행하지 않는 운영 규칙이 필요하다. DDL의 종류와 실행 시점에 따라 대기, 덤프 실패, 기대와 다른 내용이 발생할 수 있다. 행의 MVCC 스냅샷이 테이블 정의와 모든 저장 프로그램 정의를 한 시점으로 고정한다고 해석해서는 안 된다.

복제 초기화나 PITR을 위해 --source-data=2를 함께 쓰는 경우에는 덤프 시작 시 짧은 전역 읽기 잠금이 사용될 수 있다. 따라서 이 조합도 무조건 무잠금이라고 설명하면 안 된다. 이 글의 실험은 binary log 좌표를 수집하지 않는다.

2.2 엔진과 범위가 먼저다

MyISAM이나 MEMORY 테이블은 이 트랜잭션 스냅샷으로 보호되지 않는다. 혼합 엔진이면 쓰기 중지, 별도 잠금 또는 다른 백업 방식을 검토한다. 서로 참조하는 스키마를 별도 mysqldump 프로세스로 나누면 각 프로세스가 서로 다른 스냅샷을 가지므로, 스키마 간 일관성이 필요할 때는 같은 덤프 실행 범위로 묶는다.

--quick은 결과 전체를 클라이언트 메모리에 모으지 않고 행을 읽어 출력하도록 한다. 보통 기본 --opt에 포함되지만 대용량 덤프 의도를 명확히 하려면 함께 적는다. 이는 클라이언트 메모리 사용을 줄이는 옵션이지, 서버의 undo 보유 시간이나 복원 시간을 줄이는 옵션은 아니다.

3. 저장 프로그램은 존재와 실행 가능성을 함께 확인한다

3.1 프로시저·함수: 정의 복원과 권한 복원은 다르다

--routines는 프로시저와 함수의 생성문을 포함한다. DEFINER, SQL SECURITY, 문자셋, 생성 시 SQL mode와 같은 실행 의미도 검토해야 한다. 원본 계정이 없는 서버로 이관하거나 관리형 서비스의 제한된 계정으로 복원하면 생성 단계 또는 실제 호출 시 실패할 수 있다.

DEFINER를 덤프 전체에서 일괄 문자열 치환하는 방식은 권장하지 않는다. 의도한 권한 주체를 바꾸고 보안 의미를 변경할 수 있기 때문이다. 대상 계정을 준비할지, 특정 객체를 검토 후 재생성할지 정책을 먼저 정한다. Binary log가 켜진 대상에서는 저장 함수 생성 권한과 log_bin_trust_function_creators 설정도 검토하되, 복원을 통과시키기 위해 전역 보안 설정을 무조건 완화하지 않는다.

3.2 트리거: 초기 적재와 이후 업무 쓰기를 구분한다

트리거는 기본적으로 포함된다. mysqldump가 생성하는 복원 스크립트는 해당 테이블의 데이터를 적재한 뒤 트리거 정의를 생성하므로, 빈 대상에 원래 순서대로 복원할 때 기존 행의 적재가 그 트리거를 다시 실행하는 방식은 아니다.

그러나 데이터만 덤프해서 이미 트리거가 있는 테이블에 넣거나, 덤프를 분해해 트리거부터 생성하면 INSERT가 감사 행이나 집계 변경을 다시 만들 수 있다. 빈 대상에서의 전체 복원과 운영 테이블에 대한 데이터 덧씌우기를 같은 작업으로 취급하지 않는다.

3.3 이벤트: 복원 성공 직후가 위험할 수 있다

--events는 이벤트 정의를 복원 가능한 형태로 포함한다. 활성 이벤트와 실행 가능한 Event Scheduler가 함께 존재하면 복원 직후 정리·집계 작업이 시작될 수 있다. 대상이 검증 환경이어도 외부 의존성이나 공유 대상에 영향을 줄 수 있으므로 스케줄러 실행 정책, 이벤트 상태, DEFINER, 시간대와 반복 주기를 먼저 확인한다.

검증용 복원은 이벤트를 비활성 상태로 유지하고, 데이터와 의존 객체 검증 후 승인된 이벤트만 활성화한다. 아래 예제는 처음부터 이벤트를 DISABLE로 생성한다. 이벤트 정의와 비활성 상태의 보존을 확인할 뿐, 실제 예약 실행까지 검증한 예제는 아니다.

4. 재현용 스키마와 사전 점검

아래 SQL은 동명의 스키마가 없는 폐기용 서버에서 실행한다. 하나의 InnoDB 테이블에 프로시저·함수·트리거·이벤트를 각각 하나씩 연결한다. 함수는 외부 데이터를 읽지 않는 결정적 함수로 만들고, 이벤트는 실험 중 실행되지 않도록 비활성화한다.

CREATE DATABASE dump_lab CHARACTER SET utf8mb4;
CREATE TABLE dump_lab.orders (
    id INT PRIMARY KEY,
    amount INT NOT NULL,
    note VARCHAR(20) NOT NULL
) ENGINE=InnoDB;
CREATE TRIGGER dump_lab.orders_bi BEFORE INSERT ON dump_lab.orders
FOR EACH ROW SET NEW.note = UPPER(NEW.note);
CREATE PROCEDURE dump_lab.order_count()
SQL SECURITY INVOKER
SELECT COUNT(*) AS order_count FROM dump_lab.orders;
CREATE FUNCTION dump_lab.add_one(n INT) RETURNS INT
DETERMINISTIC NO SQL SQL SECURITY INVOKER RETURN n + 1;
CREATE EVENT dump_lab.daily_check
ON SCHEDULE EVERY 1 DAY DISABLE DO SELECT 1;
INSERT INTO dump_lab.orders VALUES (1, 100, 'new'), (2, 250, 'paid');
SELECT id, amount, note FROM dump_lab.orders ORDER BY id;

실행 결과(MySQL 8.0.x):

mysql> CREATE DATABASE dump_lab CHARACTER SET utf8mb4;

Query OK, 1 row affected (0.00 sec)

mysql> CREATE TABLE dump_lab.orders (
    ->     id INT PRIMARY KEY,
    ->     amount INT NOT NULL,
    ->     note VARCHAR(20) NOT NULL
    -> ) ENGINE=InnoDB;

Query OK, 0 rows affected (0.00 sec)

mysql> CREATE TRIGGER dump_lab.orders_bi BEFORE INSERT ON dump_lab.orders
    -> FOR EACH ROW SET NEW.note = UPPER(NEW.note);

Query OK, 0 rows affected (0.01 sec)

mysql> CREATE PROCEDURE dump_lab.order_count()
    -> SQL SECURITY INVOKER
    -> SELECT COUNT(*) AS order_count FROM dump_lab.orders;

Query OK, 0 rows affected (0.00 sec)

mysql> CREATE FUNCTION dump_lab.add_one(n INT) RETURNS INT
    -> DETERMINISTIC NO SQL SQL SECURITY INVOKER RETURN n + 1;

Query OK, 0 rows affected (0.00 sec)

mysql> CREATE EVENT dump_lab.daily_check
    -> ON SCHEDULE EVERY 1 DAY DISABLE DO SELECT 1;

Query OK, 0 rows affected (0.00 sec)

mysql> INSERT INTO dump_lab.orders VALUES (1, 100, 'new'), (2, 250, 'paid');

Query OK, 2 rows affected (0.00 sec)
Records: 2  Duplicates: 0  Warnings: 0

mysql> SELECT id, amount, note FROM dump_lab.orders ORDER BY id;

+----+--------+------+
| id | amount | note |
+----+--------+------+
|  1 |    100 | NEW  |
|  2 |    250 | PAID |
+----+--------+------+
2 rows in set (0.00 sec)

업무 환경에서는 스키마명을 바꾸고 동일한 점검을 수행한다. 메타데이터 조회 결과는 실행 계정의 가시성에 영향을 받으므로, 결과가 없다고 바로 객체가 없다고 판정하지 않는다.

SELECT TABLE_NAME, ENGINE
FROM information_schema.TABLES
WHERE TABLE_SCHEMA = 'dump_lab' AND TABLE_TYPE = 'BASE TABLE';
SELECT ROUTINE_NAME, ROUTINE_TYPE, SECURITY_TYPE
FROM information_schema.ROUTINES
WHERE ROUTINE_SCHEMA = 'dump_lab' ORDER BY ROUTINE_NAME;
SELECT TRIGGER_NAME, EVENT_MANIPULATION, ACTION_TIMING
FROM information_schema.TRIGGERS
WHERE TRIGGER_SCHEMA = 'dump_lab';
SELECT EVENT_NAME, STATUS
FROM information_schema.EVENTS
WHERE EVENT_SCHEMA = 'dump_lab';

실행 결과(MySQL 8.0.x):

mysql> SELECT TABLE_NAME, ENGINE
    -> FROM information_schema.TABLES
    -> WHERE TABLE_SCHEMA = 'dump_lab' AND TABLE_TYPE = 'BASE TABLE';

+------------+--------+
| TABLE_NAME | ENGINE |
+------------+--------+
| orders     | InnoDB |
+------------+--------+
1 row in set (0.00 sec)

mysql> SELECT ROUTINE_NAME, ROUTINE_TYPE, SECURITY_TYPE
    -> FROM information_schema.ROUTINES
    -> WHERE ROUTINE_SCHEMA = 'dump_lab' ORDER BY ROUTINE_NAME;

+--------------+--------------+---------------+
| ROUTINE_NAME | ROUTINE_TYPE | SECURITY_TYPE |
+--------------+--------------+---------------+
| add_one      | FUNCTION     | INVOKER       |
| order_count  | PROCEDURE    | INVOKER       |
+--------------+--------------+---------------+
2 rows in set (0.00 sec)

mysql> SELECT TRIGGER_NAME, EVENT_MANIPULATION, ACTION_TIMING
    -> FROM information_schema.TRIGGERS
    -> WHERE TRIGGER_SCHEMA = 'dump_lab';

+--------------+--------------------+---------------+
| TRIGGER_NAME | EVENT_MANIPULATION | ACTION_TIMING |
+--------------+--------------------+---------------+
| orders_bi    | INSERT             | BEFORE        |
+--------------+--------------------+---------------+
1 row in set (0.00 sec)

mysql> SELECT EVENT_NAME, STATUS
    -> FROM information_schema.EVENTS
    -> WHERE EVENT_SCHEMA = 'dump_lab';

+-------------+----------+
| EVENT_NAME  | STATUS   |
+-------------+----------+
| daily_check | DISABLED |
+-------------+----------+
1 row in set (0.00 sec)

이 목록은 덤프 전에 보관할 객체 명세의 최소 형태다. 운영에서는 뷰와 객체별 DEFINER, 권한, 참조 대상, 스케줄까지 포함한다. 백업 계정에는 대상 데이터의 SELECT, 뷰의 SHOW VIEW, 트리거의 TRIGGER, 이벤트의 EVENT 등 필요한 권한을 준비한다. 공식 mysqldump 문서는 --routines에 전역 SELECT 권한을 요구한다고 명시하므로, 전역 읽기 권한을 임의로 확대하지 말고 사용 중인 클라이언트·서버 버전과 백업 보안 정책을 함께 검토한다.

--no-tablespaces는 tablespace 생성문을 제외하고 이에 따른 PROCESS 권한 요구를 피하는 데 유용하지만, 특수 tablespace 구성을 복원해야 한다면 이를 단순한 권한 우회 옵션으로 사용하면 안 된다. MySQL 8.0.32 이상에서는 --single-transaction에 GTID 활성 상태와 --set-gtid-purged=ON 또는 AUTO가 결합될 때 RELOAD 또는 FLUSH_TABLES 권한도 관련된다.

5. 덤프 생성: 객체 범위를 명령에 고정한다

다음은 단일 업무 스키마의 논리 이관·복원 실험용 명령이다. backup은 사전에 접속 정보가 등록된 login path 이름이며 실제 환경에 맞게 준비한다. 암호를 명령행에 직접 적지 않는다. 검증에서는 폐기용 서버의 로컬 인증으로 동일한 덤프 옵션을 실행했다.

mysqldump --login-path=backup \
  --single-transaction --quick \
  --routines --triggers --events \
  --no-tablespaces --set-gtid-purged=OFF \
  --default-character-set=utf8mb4 \
  --result-file=dump_lab.full.sql dump_lab

여기서 --set-gtid-purged=OFF는 다른 서버에 단일 스키마를 논리 복원하면서 원본 서버 전체의 GTID 이력을 이식하지 않기 위한 선택이다. 이 명령은 복제 초기화나 PITR 기준 백업의 완성형이 아니다. GTID를 보존해야 하는 복구라면 이 옵션을 그대로 적용하지 말고 좌표·GTID·binary log 보관 정책부터 설계한다. OFFsql_log_bin=0 문장도 덤프에 추가하지 않으므로, 대상의 binary log가 켜져 있으면 복원 쓰기가 기록될 수 있다.

--result-file은 파일 출력 방식을 명확히 할 뿐 원자적으로 완성 파일을 만드는 기능은 아니다. 실패 시 일부 SQL만 들어 있는 파일이 남을 수 있다. 운영에서는 접근 권한이 제한된 임시 이름으로 생성하고 종료 코드, 표준 오류, 파일 존재와 크기를 확인한 뒤 완성 파일명으로 전환한다. 압축 파이프라인을 사용하면 셸의 pipefail로 앞 단계 실패까지 확인한다. --force로 오류를 무시한 덤프를 정상 백업으로 등록하지 않는다.

6. 실제 덤프·복원 비교: 정상 종료여도 객체는 빠질 수 있다

같은 원본에서 두 파일을 만들고, 매번 dump_lab을 비운 뒤 각각 복원했다. 비교 덤프는 앞 명령에서 --routines --events만 제외한 구성이다. --triggers는 그대로 유지했다. 각 단계는 같은 폐기용 MySQL 서버의 동일 스키마를 재생성한 실험이며, 업무 서버에서 따라 해서는 안 된다.

복원 명령의 구조는 다음과 같다. restore_lab login path가 가리키는 격리된 시험 대상과 스키마가 비어 있는지 먼저 확인한다. 덤프에는 테이블 삭제문이 포함될 수 있으므로 기존 업무 스키마에 실행하지 않는다.

mysql --login-path=restore_lab \
  --default-character-set=utf8mb4 dump_lab < dump_lab.full.sql

대상에는 dump_lab 스키마를 미리 생성했다. 이 예제는 --databases를 사용하지 않았으므로 데이터베이스 생성까지 자동으로 수행한다고 가정하지 않는다. 또한 저장 프로그램 본문에 dump_lab.orders가 명시되어 있으므로 대상 스키마명만 바꿔 적재하는 실험도 아니다.

검증 결과는 아래에 정리한다.

덤프·복원 비교 결과(MySQL 서버와 클라이언트 8.0.46):

복원에 사용한 덤프 원본 두 행의 모든 열 일치 프로시저 함수 트리거 이벤트
--routines --events 제외 일치 0 0 1 0
네 가지 옵션 모두 포함 일치 1 1 1 1

두 덤프 생성과 복원 명령은 모두 정상 종료했다. 즉, 종료 코드만으로 저장 프로그램 누락을 발견할 수 없었다. 전체 옵션으로 복원한 이벤트의 상태는 DISABLED였으며, 아래는 복원 후 동작 검증에서 얻은 실제 출력이다.

mysql> CALL dump_lab.order_count();
+-------------+
| order_count |
+-------------+
|           2 |
+-------------+
1 row in set (0.01 sec)
Query OK, 0 rows affected (0.01 sec)

mysql> SELECT dump_lab.add_one(41) AS function_value;
+----------------+
| function_value |
+----------------+
|             42 |
+----------------+
1 row in set (0.00 sec)

mysql> INSERT INTO dump_lab.orders VALUES (3,300,'new');
Query OK, 1 row affected (0.00 sec)

mysql> SELECT id,amount,note FROM dump_lab.orders WHERE id=3;
+----+--------+------+
| id | amount | note |
+----+--------+------+
|  3 |    300 | NEW  |
+----+--------+------+
1 row in set (0.00 sec)

복원 전후 두 원본 행의 모든 열을 비교하고, 완전한 옵션으로 복원한 뒤 프로시저를 호출해 행 수를 확인했다. 함수 add_one(41)의 반환값을 확인하고, 새 행의 소문자 note를 INSERT해 트리거가 대문자로 바꾸는지도 확인했다. 객체 수만 비교하는 것보다 실제 호출·쓰기 결과가 복원 가능성을 더 잘 보여준다.

이 실험은 MySQL 8.0 동일 서버에서 데이터와 객체 정의를 덤프·복원한 결과다. 다른 계정의 DEFINER 이관, 최소 권한 계정, 동시 DDL, 대량 데이터 복원 속도, 서버 손실 복구, GTID 연결과 PITR, Aurora 복원은 시험하지 않았다. 스케줄러가 이벤트를 실제 실행하는지도 시험하지 않았다.

7. 장애와 성능 위험을 읽는 운영 기준

관측 또는 상황 잘못된 해석 확인할 사항
덤프 파일이 크고 종료 코드가 0이다 필요한 객체도 모두 들어 있다 routines·events 포함 여부와 원본/복원 객체 목록
덤프 중 쓰기 지연이나 undo 증가가 있다 읽기 작업이므로 원인이 아니다 긴 Read View, purge 지연, 스토리지·네트워크 병목
복원 도중 권한 오류가 난다 데이터 파일 자체가 손상되었다 DEFINER, 생성 권한, 함수와 binary log 정책
복원 후 감사 행이 중복된다 트리거도 백업했으므로 문제없다 기존 트리거 위에 데이터만 적재했는지와 실행 순서
복원은 완료됐지만 예약 작업이 없다 Scheduler만 켜면 해결된다 이벤트 정의 포함 여부, STATUS, 실행 계정과 시간대
백업보다 복원이 훨씬 느리다 덤프 시간을 RTO로 잡아도 된다 INSERT 재실행, 인덱스 유지 비용, 로그·디스크 부하

장시간 덤프가 필요한 환경에서는 원본과 동일한 복구 기준을 충족하는 복제본에서 수행할지 검토한다. 다만 복제본의 지연, 필터, 지연 적용 설정은 백업에 담기는 데이터의 기준 시점을 바꾼다. “복제본이므로 부담이 없다” 또는 “원본과 항상 같다”는 전제는 피한다.

대규모 복원 시간을 만족하지 못한다면 논리 덤프를 더 압축하는 것만으로 해결하려 하지 않는다. 병렬 논리 내보내기·가져오기 도구나 대상 버전과 호환되는 물리 백업 방식까지 비교하고, 실제 복원 시간을 기준으로 선택한다.

8. Aurora MySQL에서는 관리형 백업과 목적을 나눈다

Aurora의 자동 백업은 클러스터 볼륨의 연속·증분 백업이며, 보존 기간 내 시점 복구와 클러스터 스냅샷 복구를 제공한다. 이것과 mysqldump의 SQL 논리 복원은 같은 기능이 아니다. 클러스터 단위 복구는 관리형 백업을 중심에 두고, 선택 스키마 이관·객체 검토·논리 추출에 mysqldump를 보조적으로 사용한다.

Aurora에서도 논리 덤프는 SQL 읽기 부하를 만든다. Reader에서 덤프하더라도 그 인스턴스에 적용된 상태와 스냅샷이 기준이며 writer의 방금 완료된 쓰기까지 자동으로 포함한다고 가정하지 않는다. Aurora 대상 복원에서는 Community 서버의 관리자 계정과 동일한 권한을 전제하지 말고, 지원 버전·파라미터·DEFINER 정책을 사전에 검증한다.

Event Scheduler와 이벤트의 활성화는 데이터 적재와 분리한다. 특히 운영 클러스터를 복원한 시험 환경에서는 정기 작업이 본래 업무 흐름을 중복 실행하지 않도록 통제해야 한다. 여기서 제시한 로컬 검증 결과를 Aurora에서 성공한 결과로 해석하지 않는다.

9. 복구용 백업으로 인정하기 위한 체크리스트

  • --single-transaction --quick --routines --triggers --events
  • 백업/복원 계정 권한과 DEFINER

결론

--single-transaction은 InnoDB 행 데이터의 스냅샷 경계를, --routines --triggers --events는 저장 프로그램의 포함 범위를 결정한다. 둘 중 하나가 빠지면 데이터는 맞는데 동작하지 않는 복원본, 또는 객체는 있는데 시점이 맞지 않는 복원본이 생길 수 있다.

운영 기준은 옵션 문자열이 아니라 일관성 범위 확인 → 명시적 객체 포함 → 격리 복원 → 데이터·동작 검증 → 실행 허용의 절차다. 다음 단계인 대용량 논리 백업과 PITR에서는 이 기준 위에 병렬 처리, 복원 시간, binary log 연결 경계를 추가해야 한다.

참고 문서