tom__bo’s Blog

MySQL!! MySQL!! @tom__bo

8.0.22でのprepared statementの挙動変化

概要

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)