DuckDB, CSV에서 MySQL로의 ETL

DuckDB를 ETL 도구로 활용 : CSV 데이터 → MySQL DuckDB를 통한 CSV 데이터를 MySQL로 ETL 하는 방법 ETL이란? ETL이란 Extract, Transform, Load의 약자로, 데이터를 다양한 소스에서 추출하고 변환하고 적재하는 과정 ETL을 수행하기 위해서는 여러가지 툴을 사용할 수 있는데 그 중 하나 DuckDB 활용하는 안 DuckDB DuckDB는 분석 쿼리에 최적화된 임베디드 데이터베이스 DuckDB는 PostgreSQL과 호환되는 SQL 문법을 사용하고, 여러 DB와 연결하여 데이터를 효율적으로 가져와 로컬 DuckDB에서 데이터 처리 가능 Extensions : https://duckdb.org/docs/extensions/overview ETL 예제 DuckDB에서 CSV 파일을 읽어와 테이블 생성 MySQL Extension{:target="_blank"} CREATE TABLE csv_table AS SELECT * FROM read_csv_auto('your_csv_file'); DuckDB에서 MySQL에 연결합니다. 다음과 같은 명령어를 사용할 수 있습니다. INSTALL MySQL; LOAD MySQL; ATTACH 'host=localhost user=root port=0 database=etldb' AS mysqldb (TYPE mysql) USE mysqldb; DuckDB에서 MySQL로 데이터를 적재합니다. 다음과 같은 명령어를 사용할 수 있습니다. CREATE TABLE mysqldb.etldb.csvtbl AS SELECT * FROM csv_table; 참고 MySQL LOAD DATA{:target="_blank"} CSV to SQLite3{:target="_blank"}

January 25, 2024 · Byung Kyu KIM

MySQL BinLog

MySQL BinLog (Binary Log) 설정 및 확인 MySQL Binlog https://dev.mysql.com/doc/internals/en/binary-log-overview.html{:target="_blank"} https://dev.mysql.com/doc/refman/5.7/en/replication-options-binary-log.html{:target="_blank"} 데이터 수정에 대한 정보를 포함하는 로그 파일 세트 Binlog 를 사용하는 목적 복제 : 마스터 복제 서버에서 슬레이브 서버로 보낼 명령문의 기록으로 사용 데이터 복구 : 백업 파일이 복원된, 특정 시점 이후의 데이터 복구를 위해 사용 Binlog 기록하는 방법 binlog-format STATEMENT : 이벤트에는 데이터 변경(삽입, 업데이트, 삭제)을 생성하는 SQL 문이 포함 MySQL 5.7.7 이전 버전까지 Default ROW : 행 기반 로깅: 이벤트는 개별 행의 변경 사항을 설명합니다. MySQL 5.7.7 버전 부터 Default MIXED : 기본적으로 STATEMENT 로깅, 필요에 따라 자동으로 ROW 로깅으로 전환 일관성 NDB Cluster 경우 Default STATEMENT 경우 ISOLATION LEVEL이 READ-COMMITTED 경우 복구시, Dirty Read 에 의한 일관성이 문제가 될 수 있음 ...

October 27, 2021 · Byung Kyu KIM

MySQL LOAD DATA

MySQL 테이블에 Text 파일을 빠르게 Insert 하는 방벙 MySQL LOAD DATA https://dev.mysql.com/doc/refman/8.0/en/load-data.html{:target="_blank"} The LOAD DATA statement reads rows from a text file into a table at a very high speed LOAD DATA statement 사전 준비 : secure_file_priv secure_file_priv 의 설정값이 NULL 로 되어 있는데 빈문자열로 수정해야 함 SHOW VARIABLES LIKE 'secure_file_priv' -- NULL my.cnf 에서 수정 및 재시작 필요 [mysqld] secure-file-priv="" LOAD DATA 최소 설정 LOAD DATA INFILE '/path/data.txt' INTO TABLE data_table Field and Line Handling : Default 설정 LOAD DATA INFILE '/path/data.txt' INTO TABLE data_table FIELDS TERMINATED BY '\t' ENCLOSED BY '' ESCAPED BY '\\' LINES TERMINATED BY '\n' STARTING BY '' 헤더 라인 무시 LOAD DATA INFILE '/path/data.txt' INTO TABLE data_table IGNORE 1 LINES LOAD DATA 기본 설정 (CSV) LOAD DATA INFILE '/path/data.txt' IGNORE INTO TABLE data_table FIELDS TERMINATED BY ',' OPTIONALLY ENCLOSED BY '"' ESCAPED BY '"' LINES TERMINATED BY '\n' (filed1, filed2, filed3 ) Duplicate-Key and Error Handling IGNORE : unique key 값이 있으면 새로운 행은 버려짐 default REPLACE : unique key 값 기준으로 새로운 행으로 변경 필드 개수, 순서 기본적으로 파일의 구분자 기준 순서와 필드와 1:1 매치됨 필드 지정을 통해 순서 조정 가능 파일의 구분자 필드가 많으면 : 버려짐 테이블의 필드가 많으면 : 나머지 필드는 Default 값이나 NULL 처리 (NULL 허용시) Input Preprocessing 테이블의 중간 필드를 무시 (Default 값 or NULL 처리) 하려면 @dummy 키워드로 필드 지정 필드 가공은 SET 명령으로 처리 @변수 명으로 받아서 가공후 필드에 지정할 수 있음 LOAD DATA INFILE '/path/data.txt' IGNORE INTO TABLE data_table FIELDS TERMINATED BY ',' LINES TERMINATED BY '\n' (filed1, @dummy, filed3, @var1, filed5 ) SET filed2 = CURRENT_TIMESTAMP, filed4 = @var1 * 2; Index Handling : LOAD DATA 문의 성능향상을 위한 Index check option unique index checks option : SET unique_checks = 0 SET unique_checks = 1 foreign key check option : SET foreign_key_checks = 0 SET foreign_key_checks = 1 로컬(클라이언트) 데이터 원격 INSERT https://dev.mysql.com/doc/refman/8.0/en/load-data-local-security.html{:target="_blank"} 사전 준비 : local_infile 설정 (server and client) server : local_infile 의 설정값이 ON(1) 로 수정해야 함 client : 접속시 --local-infile 옵션 추가 SHOW VARIABLES LIKE 'local_infile' ; -- OFF SET GLOBAL local_infile = 1 ; SHOW VARIABLES LIKE 'local_infile' ; -- ON LOCAL PATH 지정 LOAD DATA LOCAL INFILE ... LOAD DATA LOCAL INFILE '/path/data.txt' INTO TABLE data_table

October 13, 2021 · Byung Kyu KIM

MySQL 8 Docker Basic, Json Type 지원

MySQL 8 Docker 실행 및 백업, 복원 MySQL Docker 실행 docker-compose data:/var/lib/mysql : Data 파일 conf.d:/etc/mysql/conf.d : my.cnf 등의 설정파일 root:/root : login-path 사용시 ports : “3380:3306” : mysql port “33800:33060” : mysql-shell port version: '3' services: db: image: mysql:8 container_name: mysql8 command: --default-authentication-plugin=mysql_native_password restart: always environment: MYSQL_ROOT_PASSWORD: passwd TZ: Asia/Seoul ports: - "3380:3306" - "33800:33060" volumes: - data:/var/lib/mysql - conf.d:/etc/mysql/conf.d - root:/root volumes: data: conf.d: root: $ docker-compose up -d Creating network "mysql_default" with the default driver Creating volume "mysql_data" with default driver Creating volume "mysql_conf.d" with default driver Creating volume "mysql_root" with default driver Pulling db (mysql:8)... 8: Pulling from library/mysql e1acddbe380c: Pull complete bed879327370: Pull complete 03285f80bafd: Pull complete ccc17412a00a: Pull complete 1f556ecc09d1: Pull complete adc5528e468d: Pull complete 1afc286d5d53: Pull complete 6c724a59adff: Pull complete 0f2345f8b0a3: Pull complete c8461a25b23b: Pull complete 3adb49279bed: Pull complete 77f22cd6c363: Pull complete Digest: sha256:d45561a65aba6edac77be36e0a53f0c1fba67b951cb728348522b671ad63f926 Status: Downloaded newer image for mysql:8 Creating mysql8 ... done 연결 테스트 docker -t 옵션 제외 : the input device is not a TTY # echo 'select host, user from mysql.user' | docker exec -i mysql8 mysql -uroot -ppasswd $ docker exec -i mysql8 mysql -uroot -ppasswd <<< 'select host, user from mysql.user' mysql: [Warning] Using a password on the command line interface can be insecure. host user % root localhost mysql.infoschema localhost mysql.session localhost mysql.sys localhost root mysql: [Warning] Using a password on the command line interface can be insecure. ...

August 16, 2021 · Byung Kyu KIM

ElasticSearch to MySQL ETL

ElasticSearch to MySQL ETL 준비 curl : Http 기반 ElasticSearch Query (SQL) jq : ElasticSearch 결과 JSON 변환 (NDJSON) mysql-shell : MySQL 데이터 Bulk Insert (Json 타입의 Table) ElasticSearch Query curl 쿼리 후, 해당 내용 JSON 저장 $ curl -s -XPOST -H 'content-type: application/json' \ -d '{"query" : "select timestamp, activesession, loadavg, processor from \"mysql-perf-*\" limit 100"}' \ 'http://elasticsearch-server:7200/_sql' > result.json $ cat result.json | jq . { "columns": [ { "name": "timestamp", "type": "datetime" }, { "name": "activesession", "type": "long" }, { "name": "loadavg", "type": "float" }, { "name": "processor", "type": "float" } ], "rows": [ [ "2021-05-02T03:40:47.000Z", 2, 0.019999999552965164, 0 ], [ "2021-06-01T00:04:24.000Z", 4, 2.0399999618530273, 14.579999923706055 ], ... NDJSON 형태로 변환 jq -c : compact instead of pretty-printed output $ cat result.json | \ jq -c ' { "col": [.columns[] | .name], "row" : .rows[] } | [.col, .row] | transpose | map({ (.[0]): .[1] }) | add ' > result_t.json $ cat result_t.json | jq . { "timestamp": "2021-05-02T03:40:47.000Z", "activesession": 2, "loadavg": 0.019999999552965164, "processor": 0 } { "timestamp": "2021-06-22T05:25:24.000Z", "activesession": 3, "loadavg": 1.809999942779541, "processor": 4.599999904632568 } { "timestamp": "2021-07-01T00:04:21.000Z", "activesession": 1, "loadavg": 0.2800000011920929, "processor": 0.41999998688697815 MySQL JSON Import mysql-shell 테이블내 doc json 필드 생성 및 JSON 데이터 Row 단위 적재 # truncate table $ mysqlsh --sql user@mysql-server:3360/dbname -p<PASSWD> \ --execute 'truncate table data_table ;' # import $ mysqlsh --mysqlx user@mysql-server:3360/dbname -p<PASSWD> \ --import result_t.json --collection=data_table ...

August 15, 2021 · Byung Kyu KIM