MySQLのLIMIT句の入れ子による面白い挙動と将来リリースでの修正予定

とみたさんから、MySQLの次の次のバージョンで挙動が変更になる話を教えてもらったので、記録。

mysql> use mysql
mysql> SELECT user FROM user LIMIT 2;
+------------------+
| user             |
+------------------+
| mysql.infoschema |
| mysql.session    |
+------------------+
2 rows in set (0.00 sec)

 適当なテーブルから LIMIT句を使って2件のデータを取得したもの。これはまぁ普通の挙動。
次に、これを入れ子にしてみる。

mysql> (SELECT user FROM user LIMIT 2) LIMIT 3;
+------------------+
| user             |
+------------------+
| mysql.infoschema |
| mysql.session    |
| mysql.sys        |
+------------------+
3 rows in set (0.00 sec)

 こんな記述方法があるのか、という驚きはとりあえず横に置いておいて、いったん内側で 2件に絞ったものを、さらに3件に絞ろうとする、という指示に対して、内側の指示が無視されて3件返ってくる動作。
 この動作がMySQL 8.0.31 で変更される(ちゃんと(?) 2件のみが返ってくるようになる)というのが、リリースノート差分ウォッチャーとしての ご情報でした。

 ちなみに、私が「普通の書き方」だと考える、サブクエリを明示した記述方法なら、入れ子にしても2件のみが「正しく」返ってくる。

mysql> SELECT * FROM (SELECT user FROM user LIMIT 2) t LIMIT 3;
+------------------+
| user             |
+------------------+
| mysql.infoschema |
| mysql.session    |
+------------------+
2 rows in set (0.00 sec)


 以下は、お遊び。

もっと入れ子にしてみたり、

mysql> ((SELECT user FROM user LIMIT 2) LIMIT 3) LIMIT 4;
+------------------+
| user             |
+------------------+
| mysql.infoschema |
| mysql.session    |
| mysql.sys        |
| root             |
+------------------+
4 rows in set (0.00 sec)


内側にORDER BY をつけても変わらないことを確認したり、

mysql> (SELECT user FROM user ORDER BY user LIMIT 2) LIMIT 3;
+------------------+
| user             |
+------------------+
| mysql.infoschema |
| mysql.session    |
| mysql.sys        |
+------------------+
3 rows in set (0.00 sec)


内側と外側に ORDER BY をつけると、2件のみになることを確認したり、

mysql> (SELECT user FROM user ORDER BY user LIMIT 2) ORDER BY user DESC LIMIT 3;
+------------------+
| user             |
+------------------+
| mysql.session    |
| mysql.infoschema |
+------------------+
2 rows in set (0.00 sec)

いやそもそも、ORDER BY は外側だけでも2件になってくれることを確認したり、

mysql> (SELECT user FROM user LIMIT 2) ORDER BY user DESC LIMIT 3;
+------------------+
| user             |
+------------------+
| mysql.session    |
| mysql.infoschema |
+------------------+
2 rows in set (0.00 sec)


入れ子は少なくとも20個程度はちょろいもんらしい、ということを確認したり、

mysql> ((((((((((((((((((SELECT priv FROM global_grants LIMIT 2) LIMIT 3) LIMIT 4) LIMIT 5) LIMIT 6) LIMIT 7) LIMIT 8) LIMIT 9) LIMIT 10) LIMIT 11) LIMIT 12) LIMIT 13) LIMIT 14) LIMIT 15) LIMIT 16) LIMIT 17) LIMIT 18) LIMIT 19) LIMIT 20;
+----------------------------+
| priv                       |
+----------------------------+
| SYSTEM_USER                |
| AUDIT_ADMIN                |
| BACKUP_ADMIN               |
| BINLOG_ENCRYPTION_ADMIN    |
| CLONE_ADMIN                |
| CONNECTION_ADMIN           |
| INNODB_REDO_LOG_ENABLE     |
| PERSIST_RO_VARIABLES_ADMIN |
| REPLICATION_APPLIER        |
| SERVICE_CONNECTION_ADMIN   |
| SESSION_VARIABLES_ADMIN    |
| SYSTEM_USER                |
| SYSTEM_VARIABLES_ADMIN     |
| SYSTEM_USER                |
| APPLICATION_PASSWORD_ADMIN |
| AUDIT_ADMIN                |
| BACKUP_ADMIN               |
| BINLOG_ADMIN               |
| BINLOG_ENCRYPTION_ADMIN    |
| CLONE_ADMIN                |
+----------------------------+
20 rows in set (0.00 sec)

いろいろと遊びましたとさ。
MySQL 8.0.31 (順当にいけば 2022年10月リリース)でこれらがどう変化するのか、リリースされたら試してみたいと思います(覚えていたら)。