MySQL에서 SELECT 결과를 파일로 저장하고 복구하는 방법은 무엇인가요?
💡 MySQL의 SELECT INTO OUTFILE로 쿼리 결과를 파일로 저장하고, LOAD DATA INFILE로 파일 데이터를 테이블로 복구할 수 있습니다. 이 방법은 대용량 데이터 백업 및 마이그레이션에 유용합니다.
1. SELECT INTO OUTFILE - 쿼리 결과를 파일로 저장
1.1 기본 사용법
SELECT INTO OUTFILE은 SELECT 쿼리 결과를 서버의 파일시스템에 텍스트 파일로 저장합니다.
기본 구문:
SELECT * INTO OUTFILE '/경로/파일명.txt'
FROM 테이블명;
실전 예시:
mysql> USE mysql;
Database changed
mysql> SELECT * INTO OUTFILE '/tmp/userlist.txt' FROM user;
Query OK, 6 rows affected (0.00 sec)
생성된 파일 확인:
[root@localhost ~]# ls -l /tmp/userlist.txt
-rw-rw-rw- 1 mysql mysql 542 Feb 25 13:42 /tmp/userlist.txt
[root@localhost ~]# cat /tmp/userlist.txt
localhost root Y Y Y Y Y Y...
127.0.0.1 root Y Y Y Y Y Y...
특징:
- 탭(Tab)으로 구분된 텍스트 파일 생성
- **줄바꿈(Newline)**으로 행 구분
- 컬럼명 및 테이블 구조 제외 (순수 데이터만 저장)
- 파일이 이미 존재하면 오류 발생
1.2 파일 저장 위치
SELECT INTO OUTFILE로 생성된 파일은 MySQL 서버가 실행되는 시스템에 저장됩니다.
기본 저장 위치 (버전별):
| MySQL 버전 | 기본 저장 위치 | 설정 변수 |
|---|---|---|
| MySQL 5.5 이하 | 제한 없음 (임의 경로 가능) | - |
| MySQL 5.7 이상 | /var/lib/mysql-files/ (보안 강화) | secure_file_priv |
| MySQL 8.0 | /var/lib/mysql-files/ | secure_file_priv |
secure_file_priv 확인:
mysql> SHOW VARIABLES LIKE 'secure_file_priv';
+------------------+-----------------------+
| Variable_name | Value |
+------------------+-----------------------+
| secure_file_priv | /var/lib/mysql-files/ |
+------------------+-----------------------+
1 row in set (0.00 sec)
가능한 값:
- 경로 지정 (예:
/var/lib/mysql-files/): 해당 디렉토리만 허용 - 빈 문자열 (
''): 모든 경로 허용 (보안 위험) - NULL: SELECT INTO OUTFILE 기능 완전 비활성화
secure_file_priv 변경 방법 (my.cnf):
[mysqld]
secure_file_priv = /home/mysql/export/
변경 후 MySQL 재시작:
[root@localhost ~]# systemctl restart mysqld
1.3 CSV 형식으로 저장
쉼표(,)로 구분된 CSV 파일로 저장할 수 있습니다.
CSV 구문:
SELECT * INTO OUTFILE '/tmp/userlist.csv'
FIELDS TERMINATED BY ','
ENCLOSED BY '"'
LINES TERMINATED BY '\n'
FROM user;
생성된 CSV 파일:
"localhost","root","","Y","Y","Y","Y","Y","Y"
"127.0.0.1","root","","Y","Y","Y","Y","Y","Y"
옵션 설명:
- FIELDS TERMINATED BY ',': 필드를 쉼표로 구분
- ENCLOSED BY '"': 필드를 큰따옴표로 감쌈
- LINES TERMINATED BY '\n': 행을 줄바꿈으로 구분
- OPTIONALLY ENCLOSED BY '"': 문자열 필드만 따옴표로 감쌈
1.4 특정 컬럼만 저장
필요한 컬럼만 선택하여 저장할 수 있습니다.
SELECT host, user, password INTO OUTFILE '/tmp/user_simple.txt'
FIELDS TERMINATED BY ','
FROM mysql.user;
1.5 WHERE 조건으로 필터링
조건에 맞는 데이터만 파일로 저장할 수 있습니다.
SELECT * INTO OUTFILE '/tmp/root_users.txt'
FROM mysql.user
WHERE user = 'root';
2. LOAD DATA INFILE - 파일 데이터를 테이블로 복구
2.1 기본 사용법
LOAD DATA INFILE은 파일의 데이터를 MySQL 테이블로 가져옵니다.
기본 구문:
LOAD DATA INFILE '/경로/파일명.txt'
INTO TABLE 테이블명;
실전 예시:
1단계: 동일한 구조의 테이블 생성
mysql> CREATE TABLE user_backup LIKE mysql.user;
Query OK, 0 rows affected (0.05 sec)
2단계: 데이터 복구
mysql> LOAD DATA INFILE '/tmp/userlist.txt' INTO TABLE user_backup;
Query OK, 6 rows affected (0.00 sec)
Records: 6 Deleted: 0 Skipped: 0 Warnings: 0
3단계: 복구된 데이터 확인
mysql> SELECT host, user FROM user_backup;
+-----------------------+------+
| host | user |
+-----------------------+------+
| localhost | root |
| localhost.localdomain | root |
| 127.0.0.1 | root |
| ::1 | root |
| localhost | |
| localhost.localdomain | |
+-----------------------+------+
6 rows in set (0.00 sec)
2.2 CSV 파일 복구
CSV 형식 파일을 복구할 때는 SELECT INTO OUTFILE에서 사용한 옵션과 동일하게 지정해야 합니다.
LOAD DATA INFILE '/tmp/userlist.csv'
INTO TABLE user_backup
FIELDS TERMINATED BY ','
ENCLOSED BY '"'
LINES TERMINATED BY '\n';
2.3 컬럼 순서 지정
파일의 컬럼 순서가 테이블과 다를 경우, 명시적으로 지정할 수 있습니다.
LOAD DATA INFILE '/tmp/custom_order.txt'
INTO TABLE user_backup
(host, user, password);
2.4 중복 데이터 처리
REPLACE 옵션 - 기존 데이터 덮어쓰기:
LOAD DATA INFILE '/tmp/userlist.txt'
REPLACE INTO TABLE user_backup;
IGNORE 옵션 - 중복 데이터 무시:
LOAD DATA INFILE '/tmp/userlist.txt'
IGNORE INTO TABLE user_backup;
2.5 특정 행 건너뛰기 (헤더 제외)
CSV 파일에 헤더 행이 있을 경우, IGNORE n LINES로 건너뛸 수 있습니다.
LOAD DATA INFILE '/tmp/userlist_with_header.csv'
INTO TABLE user_backup
FIELDS TERMINATED BY ','
ENCLOSED BY '"'
LINES TERMINATED BY '\n'
IGNORE 1 LINES;
3. 실전 활용 예제
3.1 대용량 테이블 백업 및 복구
백업 (100만 행 테이블):
SELECT * INTO OUTFILE '/backup/orders_20250117.txt'
FIELDS TERMINATED BY '\t'
LINES TERMINATED BY '\n'
FROM orders
WHERE order_date >= '2025-01-01';
복구:
LOAD DATA INFILE '/backup/orders_20250117.txt'
INTO TABLE orders_backup
FIELDS TERMINATED BY '\t'
LINES TERMINATED BY '\n';
3.2 데이터베이스 간 데이터 이전
서버 A에서 데이터 추출:
-- 서버 A (source)
SELECT * INTO OUTFILE '/tmp/customers.txt' FROM customers;
파일을 서버 B로 전송:
[root@serverA ~]# scp /tmp/customers.txt root@serverB:/tmp/
서버 B에서 데이터 가져오기:
-- 서버 B (destination)
CREATE TABLE customers LIKE source_db.customers; -- 구조 복사
LOAD DATA INFILE '/tmp/customers.txt' INTO TABLE customers;
3.3 Excel에서 사용할 CSV 파일 생 성
Excel에서 읽을 수 있는 CSV 파일로 데이터를 추출합니다.
SELECT customer_name, email, phone, city INTO OUTFILE '/tmp/customer_list.csv'
FIELDS TERMINATED BY ','
ENCLOSED BY '"'
LINES TERMINATED BY '\r\n'
FROM customers
WHERE country = 'Korea';
주의: Windows Excel에서는 LINES TERMINATED BY '\r\n' 사용
3.4 정기 백업 스크립트 (Cron)
백업 스크립트 작성:
/home/scripts/daily_backup.sh:
#!/bin/bash
DATE=$(date +%Y%m%d)
BACKUP_DIR="/backup/mysql"
MYSQL_USER="root"
MYSQL_PASS="your_password"
# 테이블 백업
mysql -u ${MYSQL_USER} -p${MYSQL_PASS} <<EOF
USE mydb;
SELECT * INTO OUTFILE '${BACKUP_DIR}/users_${DATE}.txt'
FIELDS TERMINATED BY '\t'
LINES TERMINATED BY '\n'
FROM users;
EOF
echo "[$(date)] Backup completed: users_${DATE}.txt" >> /var/log/mysql_backup.log
실행 권한 부여:
[root@localhost ~]# chmod +x /home/scripts/daily_backup.sh
Cron 등록 (매일 새벽 2시):
[root@localhost ~]# crontab -e
0 2 * * * /home/scripts/daily_backup.sh
4. 권한 및 보안
4.1 필요한 권한
SELECT INTO OUTFILE 권한:
- FILE 권한 필요
권한 확인:
mysql> SHOW GRANTS FOR 'backup_user'@'localhost';
+-------------------------------------------------------+
| Grants for backup_user@localhost |
+-------------------------------------------------------+
| GRANT FILE ON *.* TO 'backup_user'@'localhost' |
| GRANT SELECT ON mydb.* TO 'backup_user'@'localhost' |
+-------------------------------------------------------+
권한 부여:
mysql> GRANT FILE ON *.* TO 'backup_user'@'localhost';
mysql> GRANT SELECT ON mydb.* TO 'backup_user'@'localhost';
mysql> FLUSH PRIVILEGES;
4.2 보안 고려사항
1. secure_file_priv 설정
- 파일 저장 경로를 제한하여 보안 위험 감소
- 프로덕션 환경에서는 반드시 설정 권장
2. 파일 권한 확인
- 생성된 파일은 mysql 사용자 소유로 생성됨
- 민감한 데이터는 권한 조정 필수
[root@localhost ~]# chmod 600 /tmp/userlist.txt
[root@localhost ~]# chown mysql:mysql /tmp/userlist.txt
3. FILE 권한 최소화
- FILE 권한은 모든 데이터베이스에 적용됨
- 꼭 필요한 사용자에게만 부여
5. 에러 및 트러블슈팅
5.1 오류: "The MySQL server is running with the --secure-file-priv option"
원인:
- secure_file_priv로 지정된 디렉토리 외에 파일을 저장하려고 시도
해결:
-- 허용된 디렉토리 확인
mysql> SHOW VARIABLES LIKE 'secure_file_priv';
-- 올바른 경로 사용
mysql> SELECT * INTO OUTFILE '/var/lib/mysql-files/userlist.txt' FROM user;
5.2 오류: "File '/tmp/userlist.txt' already exists"
원인:
- 동일한 파일명이 이미 존재함
해결:
# 기존 파일 삭제
[root@localhost ~]# rm /tmp/userlist.txt
# 또는 다른 파일명 사용
mysql> SELECT * INTO OUTFILE '/tmp/userlist_new.txt' FROM user;
5.3 오류: "Can't create/write to file '/tmp/userlist.txt' (Errcode: 13 - Permission denied)"
원인:
- MySQL 사용자(mysql)에게 디렉토리 쓰기 권한이 없음
해결:
# 디렉토리 권한 확인
[root@localhost ~]# ls -ld /tmp
drwxr-xr-x 10 root root 4096 Feb 25 13:42 /tmp
# 디렉토리 권한 수정
[root@localhost ~]# chmod 1777 /tmp
5.4 오류: "LOAD DATA INFILE: Incorrect format"
원인:
- SELECT INTO OUTFILE과 LOAD DATA INFILE의 구분자 옵션이 다름
해결:
- 저장 시 사용한 옵션과 복구 시 옵션을 동일하게 맞춤
-- 저장 시
SELECT * INTO OUTFILE '/tmp/data.txt'
FIELDS TERMINATED BY ',' ENCLOSED BY '"'
FROM mytable;
-- 복구 시 동일한 옵션 사용
LOAD DATA INFILE '/tmp/data.txt'
INTO TABLE mytable
FIELDS TERMINATED BY ',' ENCLOSED BY '"';
5.5 한글 깨짐 문제
원인:
- 파일 인코딩과 MySQL 문자셋 불일치
해결:
-- UTF-8 문자셋 명시
LOAD DATA INFILE '/tmp/userlist.txt'
INTO TABLE user_backup
CHARACTER SET utf8mb4;
6. SELECT INTO OUTFILE vs mysqldump
| 기준 | SELECT INTO OUTFILE | mysqldump |
|---|---|---|
| 속도 | 매우 빠름 | 중간 |
| 저장 내용 | 순수 데이터만 | 테이블 구조 + 데이터 (SQL) |
| 복구 용이성 | 테이블 구조 별도 필요 | SQL 파일 실행만으로 복구 |
| 대용량 데이터 | 적합 (효율적) | 적합 (대용량은 느릴 수 있음) |
| 데이터 형식 | 텍스트/CSV | SQL INSERT 문 |
| 압축 | 별도 압축 필요 | --compress 옵션 지원 |
| 트랜잭션 | 없음 (일관성 보장 X) | --single-transaction 지원 |
| 전체 DB 백업 | 불가능 (테이블별) | 가능 (--all-databases) |
권장 사용 시나리오:
- SELECT INTO OUTFILE: 대용량 테이블 단일 백업, CSV 데이터 추출
- mysqldump: 전체 데이터베이스 백업, 테이블 구조 포함 백업
7. 대안 방법
7.1 mysql 명령줄 출력 리다이렉션
[root@localhost ~]# mysql -u root -p -e "SELECT * FROM mysql.user" > /tmp/userlist.txt
7.2 mysqldump (테이블 구조 포함)
[root@localhost ~]# mysqldump -u root -p mydb mytable > /tmp/mytable_backup.sql
7.3 MySQL Workbench (GUI)
- Table Data Export Wizard 사용
- CSV, JSON, XML 등 다양한 형식 지원
8. Best Practices
-
정기 백업 자동화: Cron으로 주기적인 백업 스케줄 설정
-
백업 파일 압축: 디스크 공간 절약을 위해 gzip 압축
[root@localhost ~]# gzip /backup/users_20250117.txt -
백업 파일 원격 전송: rsync 또는 scp로 원격 서버에 백업
[root@localhost ~]# rsync -avz /backup/ backup-server:/mysql-backups/ -
트랜잭션 일관성: 트랜잭션 중에 백업하면 일관성 문제 발생 가능
- 가능하면 mysqldump의
--single-transaction사용
- 가능하면 mysqldump의
-
파일명에 날짜 포함: 백업 파일 관리 용이
userlist_20250117_020000.txt
9. 참고 자료
- MySQL 공식 문서: https://dev.mysql.com/doc/refman/8.0/en/select-into.html
- LOAD DATA INFILE 문서: https://dev.mysql.com/doc/refman/8.0/en/load-data.html
- secure_file_priv 설정: https://dev.mysql.com/doc/refman/8.0/en/server-system-variables.html#sysvar_secure_file_priv