元部下で変態なFさんがFacebookで書いてたのと、自分なりのまとめということで、簡単にDoctrine2のバルクインサートについて書いておこうと思います。
使用しているDBはMySQL想定です。
Doctrine2を使ってバルクインサートする場合は以下のようなコードになるかと思います。
<?php $batch = 1000; foreach ($entities as $key => $entity) { $em->persist($entity); if ($key % $batch == 0) { $em->flush(); } }
で、まあこれはこれでいいんですが、いくつかトラップがあると思います。
まあどれもメモリが足りなくなる問題だと思いますが・・・
- 1. clearをしていない
-
まあO/Rマッパーなんで、いろいろとメモリを食うわけです。
んで、解放しないままにしておくと、メモリが足りなくなるわけです。
これはentityManagerのclearメソッドを実行すればいいのです。<?php $batch = 1000; foreach ($entities as $key => $entity) { $em->persist($entity); if ($key % $batch == 0) { $em->flush(); $em->clear(); } }
- 2. clearしたらなんか他のエンティティを保存しようとしたらExceptionを吐く
-
どういう状況だったか忘れてしまいましたが、複数のエンティティが絡むバッチ処理を実行している際にclear()をしてしまうとエラーになるという現象が発生したことがありました。
これは多分なんですが、clear時にエンティティ名を指定しないとダメなんだと。<?php $batch = 1000; foreach ($entities as $key => $entity) { $em->persist($entity); if ($key % $batch == 0) { // Pdw\TestBundle\Entity\Hogeエンティティを扱っている事を想定 $em->flush(); $em->clear('Pdw\TestBundle\Entity\Hoge'); } }
- 3. Commandとして実行した場合にメモリが足りなくなる問題
-
ContainerAwareCommandクラスを継承した、コマンド系の処理を実行している際にメモリが足りなくなる事があります。
これは開発環境でよく起きる現象かと思っています。
実行するときに「–no-debug 」オプションをちゃんと指定すれば大丈夫です。app/console hoge:fuag --no-debug
と以上が、大まかな注意点だと使っていて感じました。
まあ僕がDcotrine2を全然使いこなせていないので、、、もっといろいろノウハウを持っている方は僕に共有してください。
有益な情報であれば鰻ぐらいはおごりますよ。
それから、DQLのパース処理が遅いのか、バルクインサートしてもなんか遅い感じがします。
1秒近く待たされてからInsert処理が実行されるぽい感じです。。
まあPDOが遅い上にDQLとか遅いのは仕方ないよねって感じですね。
あまりにも大きすぎる処理をのぞいてある程度はバッチ処理であれば、phpのメモリを512MBぐらいすれば大体たりるかなぁーというイメージです。
てか大体メモリー食う時って自分の実装が悪いってのが90%ぐらいなんで常に自分の実装を見直す癖はつけた方が良いです。
てかそもそもバッチ処理にDcotrine2を使う必要ないのでは?って思ってしまう今日この頃です。