CAKEPHP2系とか、MySQLのバッファプールにハマったので残しておく
※2018-02-25のリライト記事です。
仕事でCAKEPHP2系を触ったのですが、色々の勉強になったので残しておく。
MySQLのバッファプールに要注意
いきなりCAKEPHPの話ではなくなるのですが、「MySQLのバッファプール」ってご存知でしょうか??
バッファプールのダンプ&リストア
InnoDBには、一度アクセスしたデータをInnoDB Buffer Poolというメモリ上の領域にキャッシュしておくことで、2回目以降のアクセスを高速化する仕組みがあります。この場合、メモリ上のデータはMySQLサーバーを再起動すると消えてしまうため、再起動直後はパフォーマンスが劣化してしまう、という現象が起きます。
このような現象を防ぐために、MySQLサーバー再起動直後にバッファプール上にデータをキャッシュするための適当なクエリを実行してからアプリケーションを動かしているケースもありますが、MySQL 5.6ではバッファプールの内容をダンプ&リストアできるため、この課題を解決できます。
引用元:MySQL 5.6での機能強化点(その1) - パフォーマンスと使い勝手を大きく向上 | Think IT(シンクイット)
リファレンス:MySQL :: MySQL 5.6 リファレンスマニュアル :: 8.9.1 InnoDB バッファープール
と、ざっくりこういうものです。
結果、今回コイツが犯人で本番環境へのリリースに失敗したりと悲惨な目に合いました・・・。
そんなの知ってるわ!
ってレベルのエンジニアはこのあたりで撤退でOKだと思います。
ちなみに、バッファプールの状況調査に役立ったのはマニュアルでした。
上からよく読んで調査を実施していきましょうw
MySQL :: MySQL 5.6 リファレンスマニュアル :: 14.14.5 InnoDB INFORMATION_SCHEMA バッファープールテーブル
CakePHPのModelファイルキャッシュって??
app/tmp/cache/models/
の配下にあるアレのことです。
処理を実行すると作られるのですが、アレが結局どんな役割を果たすのかわかりませんでした。
最初アレがリリース時に初期化する運用なので、その影響で処理が遅くなるのでは?
と検証した所、早くなってしまったんですよ・・・。
本当はバッファプールが原因だったのですが。
本当に不運な事故でした。
仮説が間違っていたけど早くなるという結果が帰ってきたのでこれでOKとなってしまったんですよね(涙)
そのうちちゃんと調べるなり聞くなりして更新しようと思います・・・。
deleteAllはfindAllもやっている
消したい条件を配列に格納してやると全部消してくれて凄くスマートに書けるメソッドなのですが、コイツが中々曲者でした。
public function deleteAll($conditions, $cascade = true, $callbacks = false) {
if (empty($conditions)) {
return false;
}$db = $this->getDataSource();
if (!$cascade && !$callbacks) {
return $db->delete($this, $conditions);
}$ids = $this->find('all', array_merge(array(
'fields' => "{$this->alias}.{$this->primaryKey}",
'order' => false,
'group' => "{$this->alias}.{$this->primaryKey}",
'recursive' => 0), compact('conditions'))
);if ($ids === false || $ids === null) {
return false;
}$ids = Hash::extract($ids, "{n}.{$this->alias}.{$this->primaryKey}");
if (empty($ids)) {
return true;
}if ($callbacks) {
$_id = $this->id;
$result = true;
foreach ($ids as $id) {
$result = $result && $this->delete($id, $cascade);
}$this->id = $_id;
return $result;
}foreach ($ids as $id) {
$this->_deleteLinks($id);
if ($cascade) {
$this->_deleteDependent($id, $cascade);
}
}return $db->delete($this, array($this->alias . '.' . $this->primaryKey => $ids));
}
ようするに削除する前にDBからデータを全件取りに行ってしまっているんですよね。
まぁ 確かに安全は安全なのですが、今回の削除処理で言うと○億件削除とかとんでもないプログラムで、消すものは事前に取得できている状態なのでそのままデリート処理を走らせたかったです。
よって、IDの配列をループで回して1件ずつ削除するようにすることで実行時間が1/10くらいになりました。
スマートに書きゃ良いってものではないので要注意です。
まとめ
- CAKEPHPは大量データを処理するのに向いていない。
- そもそもPHPがダメ・・・?w(Rubyとかの方が早いと聞く)
- DBの再起動とかTableのDrop → Insert直後の処理遅延はMySQLのバッファプールも疑おう
などなど。
・・・勉強にはなったけど、正直このくらいのことがわかるエンジニアと仕事がしたいなぁ。
自分は一応管理職でプロジェクトの進行を主な業務としてます。
今回エンジニアが完全に根を上げたので久しぶりに自分で調査しました。
たまにやる分には面白い。
でも自分がこれをやると他のPJが火を吹くのです(泣)
つまり、来週も別のプロジェクトを円滑に進めるために社畜ってきます!!
頑張るぞー!(白目)