MySQL 5.7.10 の導入は見送ります
MySQL 5.7 になってからオプティマイザが賢くなったとか、かなりの期待感を持っていたため、ローカルや本番用のサーバに入れて検証をしてみました。
結論から言えば、MySQL 5.6 からデグレしています。
ちなみに、全く別件の障害対応に追われているため、原因調査はできていません・・・。
環境
問題1 MySQLのサービスが応答を返さなくなる
- 10テーブル(それぞれ数百万〜数十万件)に対してDelete文を発行
- 結果は数件削除(正しい結果)
- その後から他の接続が全くできなくなる【謎】
- サービスを再起動して、復旧
データを復元して同じクエリを流すと再現します。
また、Delete文だけでなく、Insertや大量にデータがヒットするSelectでも再現。
特徴といえば、それぞれのテーブルがパーティショニングされていることでしょうか・・・。
MySQL 5.6 では再現せず。
問題2 PKを条件に含むexists句の挙動がおかしい
SELECT A.*, B.ID, B.NAME, B.HOGE, C.ID, C.NAME, C.HOGE FROM A LEFT OUTER JOIN B ON (B.A_ID = A.ID AND B.USER_ID = ?) LEFT OUTER JOIN C ON (C.A_ID = A.ID) WHERE ( EXISTS( SELECT 1 FROM D WHERE D.A_ID = A.ID AND D.USER_ID = ? ) OR EXISTS( SELECT 1 FROM E WHERE E.A_ID = A.ID AND EXISTS( SELECT 1 FROM F WHERE F.E_ID = E.ID AND F.USER_ID = ? ) ) ) AND A.ID = ?
※実際にシステムが流したクエリに基づくため、違和感を覚えると思いますが、とりあえず事実を伝えたいのでこれで。
参照権限のチェックをクエリで表現してしまったため、ずいぶんと変なクエリですが、これを実行すると対象レコードが存在するにもかかわらず結果が0件になることがあります。
また、最後の「A.ID = ?」でPrimary Keyを条件にしていること問題のようで、「A.NAME = ?」にして完全一致で名前を入れると対象レコードが取得できます。
面白いのは「D.A_ID = A.ID」のようになっているところを「D.A_ID = ?」などにして「A.ID = ?」で指定している値を入れるとレコードが取得できます。
explainを取っていないとわかりませんが、実行順序で何か問題が起こっているものと思われます。
当然、MySQL 5.6 では再現せず。
# そもそもそんな複雑なクエリをMySQLで流すな、ということかもしれませんが。