Contenu connexe
Similaire à 大規模CSVをMySQLに入れる (20)
Plus de Shuhei Iitsuka (20)
大規模CSVをMySQLに入れる
- 2. この発表の目的
• ログデータ数年分を MySQL (RDS) に入れる。
– 30万レコード/(日・テーブル) * 365 日/年 * 3 年 * 5 テーブル
= 16 億レコードくらいの規模
– とりあえず 1 年分だけでも入れたい・・・
• 今回の苦悩を紹介することで、今後同じようなタスクに
取り組む人の参考にしてもらう。
• さらに良い方法があればぜひ紹介してください。
- 3. まず
• BULK INSERT で書いた
– ウェブアプリで API のレスポンスを格納する時にはよく使う
• Facebook の友人リストとか, 某の ID リストとか
– INSERT INTO tbl VALUES (val,val,val), (val,val,val), (val ...
• 遅すぎ。
- 4. ので
• LOAD DATA INFILE で書いた
– はやい!
– 基本的に
• “” あり→ VARCHAR, TEXT
• “” なし→ INT, FLOAT
– しかし、上手くやれば DATETIME 型に対応したり、文字列処理
しながら入れることも可能
- 5. たとえば
• こんな CSV
– “セッションID”, “Page”, “タイムスタンプ”, “Page Views”
– "10000339141949907327:6","1","2011/01/01 12:10:27",1
• こんな テーブル
– session_id VARCHAR(100) NOT NULL
– session_num INTEGER(11) NOT NULL
– to_page INTEGER(11) NOT NULL
– timestamp DATETIME NOT NULL
– page_view INTEGER(11) NOT NULL
• ちなみに、NOT NULL をつけていないカラムをキーにして走査するとパフォーマン
スが落ちる。参考 http://www.mysqlperformanceblog.com/2007/04/10/count-vs-
countcol/
- 6. ならばこんなかんじ
LOAD DATA LOCAL INFILE „hoge.csv‟ # RDS の場合 LOCAL が必要
REPLACE INTO TABLE tbl # REPLACE か IGNORE
CHARACTER SET utf8
FIELDS TERMINATED BY „,‟ # CSV なので
OPTIONALLY ENCLOSED BY „“‟ # “”囲みなので
IGNORE 1 LINES # 先頭行は無視する
(@var1, to_page, @var2, page_view)
SET
session_id = SUBSTRING(@var1, 1, LOCATE(':', @var1)-1), session_num =
SUBSTRING(@var1, LOCATE(':', @var1)+1),
timestamp = STR_TO_DATE(@var2, '%Y/%m/%d %H:%i:%s‟);
“10000339141949907327:6” → “10000339141949907327”, 6
DATETIME の型を指定する
参考 http://kedar.nitty-witty.com/blog/load-delimited-data-csv-excel-into-mysql-server
- 7. InnoDB か MyISAM か
• とりあえず InnoDB?
◯ トランザクション対応
• ウェブサービスでは必須
◯ 行ロック
✕ データサイズが大きい
• MyISAM の 2~3 倍
✕ 構造が複雑
• MyISAMを使うことに。
◯ SELECT COUNT(*) が異様に速い
• InnoDB → type=INDEX, MyISAM → type=NULL
• 参考 http://opendatabaselife.blogspot.jp/2009/10/myisaminnodb.html
✕ テーブルロック
• バッチ、SELECT 中心なら MyISAM がいいかも
• ウェブで使うなら InnoDB
– 参考 http://nippondanji.blogspot.jp/2009/02/myisaminnodb.html
- 8. 高速化のために
• EXPLAIN をつかってチューニング
– select_type → type の順にチューニング
• できるだけ SUBQUERY はつかわない
– SELECT ... WHERE IN (SELECT ...) みたいなやつ
– 基本的に LEFT JOIN で書き換えられるはず
– select_type = SINPLE を目指す
• 具体的なことは・・・
http://nippondanji.blogspot.jp/2009/03/mysql_25.html
• INDEX で絞る
– type = ALL(フルテーブルスキャン)または
type = INDEX(フルインデックススキャン)は要改善。
• key_len が短くなるように
– UTF-8 の場合、 “123” は 9, 123 は 3
参考 http://nippondanji.blogspot.jp/2009/03/mysqlexplain.html
- 10. まとめ
• 基本的に InnoDB。しかし、書き込みをしない、全文検
索したいなど、特別な状況では MyISAM を検討しても
よい。
• LOAD DATA INFILE 構文のオプションを使いこなせば、
大抵のことはできる。
• 無駄なく適切なデータ型でスキームを書くべし。
• 高速化のためには EXPLAIN でチューニングを行うべ
し。