LOAD DATA(LOCAL) INFILE
1. 데이터 파일의 값과 테이블의 컬럼의 개수가 동일한 경우
desc employees;

LOAD DATA INFILE '/tmp/employees.csv'
IGNORE INTO TABLE employees
FIELDS
TREMINATED BY ','
OPTIONALLY ENCLOSED BY '"' ESCAPED BY '"'
LINES
TERMINATED BY '\n'
STARTING BY ''
(emp_no, birth_date, first_name, last_name, gender, hire_date);
IGNORE : Primary Key나 Unique Key에 의해 중복 에러가 발생해도 해당 레코드는 무시하고 계속 작업을 진행
REPLACE : 저장하려는 레코드가 중복된 레코드면 UPDATE를 실행
/tmp/employees.csv
-------------------------------------------------------------------------------------------------------------------------------
10001,"1953-09-02","Georgi","Facello","M","1986-06-26"
10002,"1964-06-02","Bezalel","Simmel","F","1985-11-21"
10003,"1959-12-03","Parto","Bamford","M","1986-08-28"
10004,"1954-05-01","Chirstian","Koblick","M","1986-12-01"
10005,"1955-01-21","Kyoichi","Maliniak","M","1989-09-12"
10006,"1953-04-20","Anneke","Preusig","F","1989-06-02"
-------------------------------------------------------------------------------------------------------------------------------
LOAD DATA INFILE 문장에 명시되는 데이터 파일은 항상 MySQL 서버가 기동 중인 장비의 디렉터리에 존재해야 한다. 하지만 INFILE 옵션 앞에 LOCAL이라는 키워드를 추가하면 MySQL서버가 아니라 클라이언트 컴퓨터의 디스크에 있는 데이터 파일을 사용할 수도 있다. 또한, MySQL 서버나 클라이언트와 무관한 서버에 있는 데이터 파일을 URL 형태로 명시할 수도 있다.
MySQL 5.1.7부터는 mysqlimport 유틸리티에 "--use--threads" 옵션을 사용하면 병렬로 LOAD DATA INFILE 명령을 실행하기 때문에 파일이 많은 경우 빠르게 적재할 수 있다. LOAD DATA INFILE 명령이나 mysqlimport 유틸리티 모두 입력 파일은 CSV 포맷과 같이 구분자로 구분된 데이터 파일어어야 한다. mysqldump 유틸리티를 이용해 덤프받은 파일은 csv포맷의 파일이 아니라 사용할 수 없다.
2.데이터 파일의 값의 개수가 테이블의 컬럼 수보다 적은 경우
birth_date 컬럼에 값이 없을 때 현재 시간을 저장하기 위해 "SET birth_date=now()"절을 추가한다. NULL이 허용되는 컬럼이라면 SET절에 명시하지 않아도 된다.
LOAD DATA INFILE '/tmp/employees.csv'
IGNORE INTO TABLE employees
FIELDS
TREMINATED BY ','
OPTIONALLY ENCLOSED BY '"' ESCAPED BY '"'
LINES
TERMINATED BY '\n'
STARTING BY ''
(emp_no, first_name, last_name, gender, hire_date)
SET birth_date=NOW();
LOAD DATA INFILE 명령의 입력 데이터는 하나의 라인에 값이 5개만 존재해야 한다.
/tmp/employees.csv
-------------------------------------------------------------------------------------------------------------------------------
10001,"Georgi,Facello","M","1986-06-26"
10002,"Bezalel,Simmel","F","1985-11-21"
10003,"Parto,Bamford","M","1986-08-28"
10004,"Chirstian","Koblick","M","1986-12-01"
10005,"Kyoichi","Maliniak","M","1989-09-12"
10006,"Anneke","Preusig","F","1989-06-02"
-------------------------------------------------------------------------------------------------------------------------------
3. 데이터 파일의 값의 개수가 테이블의 컬럼 수보다 많은 경우
데이터 파일의 두 번째 값인 "사원전화번호"는 employees 테이블에 저장할 필요가 없어서 @emp_tel_no 변수에 담아서 사용하지 않고 버린다.
LOAD DATA INFILE '/tmp/employees.csv'
IGNORE INTO TABLE employees
FIELDS
TREMINATED BY ','
OPTIONALLY ENCLOSED BY '"' ESCAPED BY '"'
LINES
TERMINATED BY '\n'
STARTING BY ''
(emp_no, @emp_tel_no, birth_date, first_name, last_name, gender, hire_date);
/tmp/employees.csv
-------------------------------------------------------------------------------------------------------------------------------
10001,"010-1234-1234","1953-09-02","Georgi","Facello","M","1986-06-26"
10002,"010-1234-1234","1964-06-02","Bezalel","Simmel","F","1985-11-21"
10003,"010-1234-1234","1959-12-03","Parto","Bamford","M","1986-08-28"
10004,"010-1234-1234","1954-05-01","Chirstian","Koblick","M","1986-12-01"
10005,"010-1234-1234","1955-01-21","Kyoichi","Maliniak","M","1989-09-12"
10006,"010-1234-1234","1953-04-20","Anneke","Preusig","F","1989-06-02"
-------------------------------------------------------------------------------------------------------------------------------
4. 데이터 파일의 값을 연산해서 테이블의 컬럼에 저장하는 경우
데이터 파일에 있는 값을 연산을 거친 후 테이블에 저장할 때 사용자 변수에 값을 담아 SET절을 이용해 연산 후에 지정한 컬럼에 값을 저장한다. 아래 예제는 @middle_name 과 @last_name 으로 컬럼에 읽어 들이 후 SET절에서 두 개 변수의 값을 문자열 결합 함수를 이용해 last_name 에 저장한다.
LOAD DATA INFILE '/tmp/employees.csv'
IGNORE INTO TABLE employees
FIELDS
TREMINATED BY ','
OPTIONALLY ENCLOSED BY '"' ESCAPED BY '"'
LINES
TERMINATED BY '\n'
STARTING BY ''
(emp_no, birth_date, first_name,@middle_name, @last_name, gender, hire_date)
SET last_name=concat(@middle_name, ' ', @last_name);
/tmp/employees.csv
-------------------------------------------------------------------------------------------------------------------------------
10001,"1953-09-02","Georgi","mid","Facello","M","1986-06-26"
10002,"1964-06-02","Bezalel","mid","Simmel","F","1985-11-21"
10003,"1959-12-03","Parto","mid","Bamford","M","1986-08-28"
10004,"1954-05-01","Chirstian","mid","Koblick","M","1986-12-01"
10005,"1955-01-21","Kyoichi","mid","Maliniak","M","1989-09-12"
10006,"1953-04-20","Anneke","mid","Preusig","F","1989-06-02"
-------------------------------------------------------------------------------------------------------------------------------
5. 데이터 파일이 MySQL 서버가 아닌 다른 컴퓨터에 있을 경우
적재하려는 데이터 파일이 MySQL 서버가 아니라 다른 원격 컴퓨터에 있을 때는 LOCAL 키워드를 추가한다. LOAD DATA LOCAL INFILE 문장이 실행되면 MySQL 서버는 적재할 데이터 파일이 MySQL 서버의 디스크가 아니라 클라이언트의 디스크에 있다고 판단한다. 그리고 MySQL 클라이언트나 JDBC 드라이버는 그 데이터 파일을 찾아서 MySQL 서버로 업로드한 후 파일을 테이블에 적재한다.
자바 프로그램에서 JDBC 드라이버를 사용해 LOAD DATA LOCAL INFILE .. 명령을 사용할 때는 파일 경로에 URL을 사용할 수 있다. 파일 경로에 URL을 사용할 수 있다는 것은 데이터 파일이 MySQL 서버와 클라이언트 컴퓨터 이외의 호스트에 위치할 수도 있다는 의미다.
HTTP 프로토콜을 이용해 제3의 서버에서 데이터 파일을 가져와 다시 원격지의 MySQL서버에 적재할 수 있다면 작업을 상당히 간단히 만들 수 있다. 아래 예제는 로컬에서 타겟 MySQL 접속 후 LOAD DATA 명령을 실행하는 것이다.
Connection conn = DriverManager.getConnection(
"jdbc:mysql://mysql_servier_ip:3306/employees?allowUrlInLocalInfile=true",userid, userpassword);
Statement stmt = conn.createStatement();
stmt.executeUpdate("LOAD DATA LOCAL INFILE 'http://another-server-url/employees.csv' "
+ "IGNORE "
+ "INTO TABLE temp_employees "
+ "FIELDS "
+ " TERMINATED BY ',' "
+ " OPTIONALLY ENCLOSED BY '\"' ESCAPED BY '\"' "
+ "LINES "
+ " TERMINATED BY '\r\n' "
+ " STARTING BY '' "
+ " (emp_no, birth_date, first_name, last_name, gender, hire_date) ");
LOAD DATA INFILE 명령의 입력으로 URL을 사용하려면 JDBC 커넥션을 생성할 때 allowUrlInLocaInfile 옵션을 ture로 설정해야 한다. 보안상의 이유로 기본값이 false로 설정돼어 있어서 LOAD DATA LOCAL INFILE 'URL' ... 명령을 사용할 수 없다.
6. LOAD DATA INFILE의 성능 향상
LOAD DATA INFILE 명령으로 대량의 데이터를 적재할 때 더욱 빠른 처리를 위해서는 다음 옵션들을 함께 사용하는 것이 좋다. AUTO-COMMIT 모드와 FOREIGN KEY는 InnoDB 테이블에 해당하며 유니크 인덱스는 모든 스토리지 엔진의 테이블에 해당하는 내용이다.
1) AUTO-COMMIT
InnoDB 스토리지 엔진에서는 트랜잭션을 사용할 수 있다. AUTO-COMMIT이 활성화(true)된 상태에서는 레코드 단위로 INSERT될 때마다 COMMIT을 실행하는데, 이 작업은 매번 레코드 단위로 로그 파일의 디스크 동기화(FLUSH) 작업을 발생시킨다. 단순히 쿼리 문장을 하나씩 실행하는 경우에는 크게 영향이 없을 수도 있지만 대량으로 INSERT 문장을 실행하는 경우에는 디스크 I/O에 상당히 많은 부하를 일으킨다.
set autocommit = 0;
LOAD DATA ...
COMMIT;
set autocommit = 1;
show variables like 'autocommit'

show variables like 'autocommit'

2) UNIQUE INDEX
만약 대량으로 데이터를 적재하는 대상 테이블에 UNIQUE 인덱스가 있다면 매번 레코드 단위로 중복 체크가 발생한다. 중복 체크라는 것은 결국 INSERT를 수행하기 전에 SELECT를 한 번씩 더 실행해야 한다는 것을 의미한다. unique_checks 설정을 변경해 중복 체크를 건너 띄도록 설정할 수 있다. 유니크 인덱스의 중복 체크 작업을 비활성화하면 중복 체크를 위한 SELECT를 생략할 수 있을 뿐더러 유니크 인덱스에 대해서도 InnoDB의 인서트 버퍼(Insert buffer)를 사용할 수 있기 때문에 상당히 많은 디스크 I/O를 줄일 수 있다.
set unique_checks = 0;
LOAD DATA ..
set unique_checks = 1;
show variables like 'unique_checks';

show variables like 'unique_checks';

3) FOREIGN KEY
데이터를 적재하는 테이블에 FOREIGN KEY가 있다면 매번 레코드의 INSERT 시점마다 FOREIGN KEY값이 존재하는지 여부를 확인해야 한다. 이 작업 또한 상당한 디스크 I/O를 유발한다. foreign_key_checks 설정을 변경하면 FOREIGN KEY의 무결성 체크를 수행하지 않고 바로 적재할 수 있다. 물론 이 경우 또한 FOREIGN KEY의 무결성을 해치는 데이터가 없다는 것을 먼저 확인해야 한다.
set foreign_key_checks=0;
LOAD DATA..
set foreign_key_checks=1;
show variables like 'foreign_key_checks';

show variables like 'foreign_key_checks';

7. LOAD DATA 명령의 문자집합 처리
LOAD DATA 명령을 이용해 파일을 테이블에 적재할 때는 특별히 문자 셋에 주의해야 한다. 먼저 LOAD DATA 명령으로 적재하려는 데이터 파일이 어떤 문자집합으로 저장됐는지 알고 있어야 한다. 그렇지 않으면 한글이나 일본어와 같이 아시아권 언어는 깨진 상태로 테이블에 적재될 수도 있다. 일반적으로 한글 윈도우에서 별다른 설정 없이 저장했다면 MS949 문자집합인 경우가 많다. 그 밖에 별도로 문자집합을 지정했다면 UTF-8일 가능성이 높다.
LAOD DATA 명령에 별도로 문자집합을 지정하지 않는 경우라면 적재하려는 데이터 파일의 문자집합은 MySQL클라이언트의 문자집합과 일치해야 한다. 우선 MySQL 커넥션의 문자집합을 다음과 같이 SHOW명령으로 확인해 보자.
show variables like 'character_set_%';

적재하려는 데이터 파일의 문자집합이 MS949나 EUC-KR이라면 클라이언트와 커넥션의 문자집합을 euckr로 변환해야 한다.
set names 'euckr';
show variables like 'character_set_%';

LOAD DATA 명령에서 데이터 파일의 문자집합을 명시할 수 있다.
LOAD DATA INFILE '/tmp/employees.csv'
IGNORE
INTO TABLE employees CHARACTER SET 'euckr'
FILEDS
TREMINATED BY ','
OPTIONALLY ENCLOSED BY '"' ESCAPED BY '"'
LINES
TERMINATED BY '\n'
STARTING BY ''
(emp_no, birth_date, first_name, last_name, gender, hire_date);
데이터 파일의 문자집합이 UTF-8이라면 EUC-KR 대신 utf8을 사용해 커넥션이나 클라이언트의 문자집합을 변경하면 된다.
set names 'utf8';
show variables like 'character_set_%';

LAOD DATA 명령에서 파일의 문자집합을 utf8로 변경해도 된다.
LOAD DATA INFILE '/tmp/employees.csv'
IGNORE
INTO TABLE employees CHARACTER SET 'utf8'
FILEDS
TREMINATED BY ','
OPTIONALLY ENCLOSED BY '"' ESCAPED BY '"'
LINES
TERMINATED BY '\n'
STARTING BY ''
(emp_no, birth_date, first_name, last_name, gender, hire_date);
'MySQL > MySQL' 카테고리의 다른 글
| 사용자 정의 변수 (0) | 2024.12.10 |
|---|---|
| UPDATE (0) | 2024.12.10 |
| INSERT INTO .. ON DUPLICATE KEY UPDATE.. (0) | 2024.12.10 |
| AUTO_INCREMENT (0) | 2024.12.10 |
| 서브쿼리 (0) | 2024.12.09 |












































































