仕事と晩飯とその他

日記です。

ついに大量のINSERTを攻略 〜闘いはこれからだ!

openBDの80万件超のデータ(和書のみ)、当初、「社長のpython」で決めようかと思ったが、pythonもう少し勉強してからにしたいので断念。続いて河村さんのjavascript、捨てる部分を決定という方法はスマートだなあと思ったが、「車輪の再発明になっても自分でやってみたほうが後々の運用考えるといい」と思い直したのと、日付で差分だとあとで別の問題(既刊の更新)が発生するのが見えてきたので断念。あ、既刊の更新が発生するのが分かっているのはインサイダー(JPOの委員)だからです。

とりあえず慣れ親しんだ(というほど使えていないが)PHPでやってみようということに。

ところが、動かない動かない。サーバー固まる固まる。データ量が多過ぎるみたい。なるほど、それで社長は分割していたのかと思いつつ、PHPでどうしたらいいのかイマイチわからない。file_get_contentsじゃダメなのを理解するまでしばらくかかった。じゃどうするのかとなると、どうしていいのかわからない。が、基本に戻ってfopenとfgets。なんとかファイルで落とすところまでたどり着いた。さて、次はそれをDBにINSERT。そこでまたはまる。そして「LOAD DATA INFILE」が使えないことを知って絶望。落とす方を分けることにする。ここでさらに戻ってfopenとfgetc。やってるうちに、「あれ、これってXMLReaderと同じこと?」と思いつく。コード書いてる割に原理をまったく理解できていないのだが、ここへきてようやく自分のやってることを明確に把握。そうか、そういうことだったのか。そして、これが面倒だから皆PHPの関数を探すのか。なるほどなるほど!

分かってしまうと分割して落とすところまでは完璧(だと思う)。問題はINSERT。一部だけはINSERTできるようになった! でも途中で止まる。504 gateway timeoutとの格闘。なぜ、タイムアウトしてしまうのか。原因がわからない(まあ、INSERTなんだけど)。解決策も見えてこない。もはやここまでかと思ったところで色々検索していたら「INSERTはVALUEをまとめてクエリー書くと早いよ」という記事を発見。試しに千件まとめたクエリーでやってみっか。

お、おおおおおおお!

できた。できたよ。ついに出来たよ!

で、そこからさらに不要な改行を削ったり(すげえ悩んだけどrtrim一発だった。そのための関数なんだな、rtrim)、WHILEのループ修正したり和書だけに絞り込んだり等々。もうこのあたりになってくると自分が何やってるのかわかってるので早い。

できた。これで、いつでも80万件超のJSONをDBに読み込める。

これでやっと始められる。


7/4追記
結論から言うと「テキストに書き出してから読み込む」手順は不要だった。これでうまくいくならfopenとwhile(!feof($fp))でぐるぐる回してもうまくくだろうと思ってやってみたらうまくいかん。何が問題なのかあらためて調べてみたら、「読み込むURLの指定」が間違ってた。というか、mysqlのhostも$urlで指定してるんで、そっちをfopenしようとしていやがった。で、そこ直したら解決。びっくりするほど速い。快適。