ある日、 mysqli からクエリ発行するとこんなエラーが・・・
1 |
Warning: mysqli_multi_query() : MySQL server has gone away in ... |
server has gone away ・・・?
あまり見かけないエラーだったので困惑、解決策を見つけるのにかなり苦戦しました。
ここでは同じようなエラーが悩む人のために、
MySQLで MySQL server has gone away エラーが出た時の対処法をまとめます。
このページの目次
このエラーに遭遇したのは multi_query を使った時
PHPの myslqi では mysqli::multi_query を使うと複数クエリが実行できます。
▼この記事で詳しく解説したやつ
このエラーに遭遇したのは、それを使って大規模クエリを実行しようとしたとき
例えばこんな感じでクエリ実行のコードを書いてたんです。
1 2 3 4 5 6 7 8 9 10 11 |
/// 実行したいクエリ(複数) $sql = " INSERT INTO tbl_001 (key, value) VALUES ('x_1', 248), ('y_1', 163); INSERT INTO tbl_002 (key, value) VALUES ('x_2', 264), ('y_2', 128); -- こういうのが延々と続く... "; /// 複数クエリ実行 $mysqli->multi_query( $sql ); |
まあ実際はこんなコードじゃないですが・・・
こういう風に セミコロン( ; ) で区切ったクエリは muitl_query から実行できます。
それで問題だったのが、実行すべきクエリがものすごく多かったことですね。
多分少なくても 1000 以上はあったと思います。
そのせいでサーバーに負荷がかかりすぎたのか、このエラーが出たみたいです。
1 |
Warning: mysqli_multi_query() : MySQL server has gone away in ... |
こういう初めて見るエラーに遭遇すると、解決策を見つけるのに苦労します。
でもいくつか解決策を試したところ、無事クエリ実行できるようになりました。
MySQL server has gone away の3つの対処法
その対処法は「これだ!」って断言はできません、いろんな原因があるので
でも最低限、次のいずれかを試せば解決するはず
解決策1.パケットサイズを必要なだけ拡張する
大規模なクエリを実行したい場合、
例えばさっきの例だと大量の INSERT をしてエラーが出てしまいました。
パケットサイズが小さすぎると、SQL実行が拒否されてしまうみたいです。
なので対処法1つめは max_allowed_packet のサイズ拡張
やり方は SQL 発行前に次のクエリを実行すればいいです(オブジェクト指向型の場合)
1 |
$mysqli->query( 'SET GLOBAL max_allowed_packet = 33554423;' ); |
この max_allowed_packet にはパケットの上限をバイト数で渡せばOK
上の例だと 33554423バイト = 約32MB まで拡張させてます。
巨大なクエリを実行できないなら、このパケットサイズをまず疑いましょう。
あとちなみに・・・
この max_allowed_packet の値は次クエリを実行すれば確認可能
1 2 3 4 |
$rst = $mysqli->query( "SHOW VARIABLES LIKE 'max_allowed_packet'" )->fetch_array(); echo 'max_allowed_packetの値 : ' . $rst['Value'] . 'バイト<br>'; |
▼上コードの出力結果
1 |
max_allowed_packetの値 : 33554423バイト |
まあ 32MB もあれば、大規模なクエリでも実行できると思います。
対処法2.MySQLのタイムアウト時間を長くする
処理に時間がかかるようなクエリの場合、
あまりにも時間がかかりすぎると、MySQL側で勝手にタイムアウトしてしまいます。
それを伸ばすには wait_timeout の値を変更が必要
例えば大規模なクエリ発行前に、
次みたいに書けば
wait_timeout の値を変更できます。
1 |
$mysqli->query( 'SET GLOBAL wait_timeout=3600;' ); |
この wait_timeout の時間単位は秒(s)
上の例だと 3600秒 なので1時間 に設定してます。
このタイムアウト時間は、大規模なら1時間以上 に設定するのが安全かもしれません。
対処法3.ini_setでタイムアウト設定も必要かも...
あとそれから、念のため・・・
自分はタイムアウト時間も init_set から設定してます。
▼ 例えばこんな感じで
1 2 3 |
/// MySQLの最大実行時間を設定 ini_set( 'mysql.connect_timeout', 60*60 ); ini_set( 'default_socket_timeout', 60*60 ); |
これは必ずしも必要ないと思いますけどね。
でもこの設定が聞いてくる場面もあると思うので、
心配ならこの設定も書いておくと問題解決につながるかも(確証はできない)
ここまでのまとめ
ということで、簡単にエラーの対処法まとめ
- パケットサイズを拡張する
クエリ実行前に max_allowed_packet の値からバイト数で指定する。大体 10MB ~ 20MB 以上にしておけば問題ないはず(ただしクエリの大きさによる)
- MySQLのタイムアウト時間を長くする
クエリ実行前に wait_timeout の値を秒で指定する。もしパケットサイズが十分大きいのに実行できないなら、この値を変更すると上手くいくはず
- ini_setでタイムアウト設定
タイムアウト時間を ini_set を使ってPHP側からも設定しておく。念のため
もし server has gone away... エラーが出てしまったら、
この3つのいずれかを試せばクエリ実行ができるようになるはずです。
以上、PHPで MySQL server has gone away.. が発生したときの対処法でした。ではまた