概要
8.0.22のリリースノートを見るとprepared statementの挙動が変わっているらしい。
特にこれが気になったので、試してみる
For a prepared statement of the form SELECT expr1, expr2, ... FROM table ORDER BY ?, passing an integer value N for the parameter no longer causes ordering of the results by the Nth expression in the select list; the results are no longer ordered, as is expected with ORDER BY constant.
どうやら8.0.22からはSELECT expr1, expr2, ... FROM table ORDER BY ? といったクエリをprepareして、placeholderにselect listの番号を表す数値Nを指定する場合にsortが効かなくなるらしい
実験
8.0.21, 8.0.22をdockerで用意して以下のようにテーブルを作成
CREATE DATABASE sample; use sample; CREATE TABLE `t1` ( `id` int NOT NULL AUTO_INCREMENT, `c1` int NOT NULL, PRIMARY KEY (`id`) ); insert into t1 (c1) values (rand()*100), (rand()*100), (rand()*100), (rand()*100), (rand()*100);
以下のクエリで検証する
PREPARE p1 FROM 'SELECT id, c1 FROM t1 ORDER BY ?'; SET @val=2; EXECUTE p1 USING @val;
結果
- 8.0.21 (order byが効く)
mysql> EXECUTE p1 USING @val; +----+----+ | id | c1 | +----+----+ | 5 | 12 | | 3 | 25 | | 1 | 62 | | 4 | 77 | | 2 | 82 | +----+----+ 5 rows in set (0.00 sec)
- 8.0.22 (order byが効かない)
mysql> EXECUTE p1 USING @val; +----+----+ | id | c1 | +----+----+ | 1 | 85 | | 2 | 41 | | 3 | 52 | | 4 | 37 | | 5 | 30 | +----+----+ 5 rows in set (0.01 sec)
個別にinsertしたのでデータは異なるが、8.0.22では確かにソートされなくなっている。 結構特殊なケースかも知れないが、8.0.22に移行するときはこれがないか確認する必要はある。
対策はなさそう。。。
アプリ側のコードで確認できれば良いけど、ある時点でprepareされているものをMySQLから確認するなら以下
mysql> SELECT STATEMENT_NAME, SQL_TEXT FROM performance_schema.prepared_statements_instances; +----------------+----------------------------------+ | STATEMENT_NAME | SQL_TEXT | +----------------+----------------------------------+ | p1 | select id, c1 from t1 order by ? | +----------------+----------------------------------+ 1 row in set (0.00 sec)