メインコンテンツまでスキップ

MySQL8 LOADでCSV取り込み

  • バルクインサートより早い。
  • カラムの順にloadされる
  • 先頭行にカラム名は要らない

csvの置き場

ファイルはsecure_file_priv で指定されているディレクトリに置くと読み取りが楽。

でないと↓のエラーで怒られるので設定を変えて再起動が必要となる。 ERROR 1290 (HY000): The MySQL server is running with the --secure-file-priv option so it cannot execute this statement

デフォルトは /var/lib/mysql-files/

SHOW VARIABLES LIKE '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)

LOAD

テーブル

CREATE TABLE `user` (
`id` int NOT NULL AUTO_INCREMENT,
`name` text NOT NULL,
PRIMARY KEY (`id`)
)

CSV

users.csv
1,i0VpEBOWfbZAVaBSo63bbH6xnAbnBE
2,oonCrbZINl91huSS6AZPsK20FKcpXz
3,kIRPxBFWGyEbcR8KykF8VH1oF7JCqH
LOAD DATA INFILE '/var/lib/mysql-files/users.csv' INTO TABLE hogedb.user FIELDS TERMINATED BY ',';

速度感

テーブル構造

100行、107MBのCSV、外部キー制約ありで11秒くらい。

$ head -n 3 articles.csv
1,76dfZTPtLLKjAyS96HBqcbCtx3GIobuiF9Pl3XT4VWv87jUSCGE5FZv23CJ5SEnuRk4q4t7RFGOKtmF5MeYT4lUdOqo2gG0pn2AS,323
2,bwkPf7bTbpYjlQxc9jcvMUhubBVT3U1RDnOtgB2hKyFi7qLAbIidcjfNF859oBpKMXRpAGaczgSoglonGCtNn47TAFKdzGlfXwG5,123
3,Lr8xbQgs0PaBzEmKerx5eUlJyCUyhhe0N7QbOWSEwCXqGD7X5ZsoEqAQ4KYfw9jzef39OhsoPQBGgH6UfGSp3CRz9WJiBbK2lFDz,144

$ wc -l articles.csv
1000000 articles.csv

$ du -sh articles.csv
107M articles.csv
mysql> LOAD DATA INFILE '/var/lib/mysql-files/articles.csv' INTO TABLE hogedb.article FIELDS TERMINATED BY ',' (id,content,user_id);
Query OK, 1000000 rows affected (12.10 sec)

外部キー制約のチェックを無視すると1.25倍くらい速くなる。

mysql> SET foreign_key_checks = 0;
Query OK, 0 rows affected (0.00 sec)

mysql> LOAD DATA INFILE '/var/lib/mysql-files/articles.csv' INTO TABLE hogedb.article FIELDS TERMINATED BY ',' (id,content,user_id);
Query OK, 1000000 rows affected (9.71 sec)

Troubleshoot

LOAD 中に外部キーを無視したい

SET foreign_key_checks = 0;

を実行してからLOADする。

CSVに一部のカラムしか含まれていない

  • id autoincrementとかtimestamp = now()を使いたいケースに
    • timestampはcsvすべての行で同じになる
  • テーブル構造変えた後とかに
ERROR 1261 (01000): Row 1 doesn't contain data for all columns

こんなエラーが出たらカラムリストを明示的に指定することで回避できる

LOAD DATA INFILE '/var/lib/mysql-files/users.csv' INTO TABLE hogedb.user FIELDS TERMINATED BY ',' (id,name);

カラムの順序はcsvの並びで指定する。