• 欢迎访问DBA的辛酸事儿,推荐使用最新版火狐浏览器和Chrome浏览器访问本网站
  • 欢迎大家关注博主公众号:DBA的辛酸事儿
  • 博文中若有错误的地方,请大家指正,大家的指正是我前进的动力

MySQL与MariaDB对子查询中order by的处理的差异

MySQL SEian.G 5年前 (2019-02-26) 2826次浏览 已收录 2个评论

02-23无意中在在论坛看到一个帖;具体的问题大概就是MySQL与MariaDB对子查询中order by的查询结果不一样;

具体的问题的描述看查看如下的连接;论坛帖子连接:https://bbs.csdn.net/topics/392517765

然后帖子中所描述的问题,我也比较好奇,所以下面就根据提供的信息来实验一下;下面的实验是在mysql和mariadb环境进行的测试;

MariaDB数据库

1、创建实验表

wjq@118.89.xxx.xxx [wjqdb]>CREATE TABLE `points` (
    ->   `id` int(10) unsigned NOT NULL AUTO_INCREMENT COMMENT 'ID',
    ->   `activity_id` int(10) unsigned NOT NULL DEFAULT 0 COMMENT '项目',
    ->   `customer_id` int(10) NOT NULL DEFAULT 0 COMMENT '用户',
    ->   `point` int(10) NOT NULL DEFAULT 0 COMMENT '积分值',
    ->   `ranking` int(10) unsigned NOT NULL DEFAULT 0 COMMENT '当前排行',
    ->   `create_time` int(10) unsigned NOT NULL DEFAULT 0 COMMENT '创建时间',
    ->   `update_time` timestamp NOT NULL DEFAULT current_timestamp() ON UPDATE current_timestamp() COMMENT '最后更新时间',
    ->   PRIMARY KEY (`id`) USING BTREE,
    ->   UNIQUE KEY `uni_activity_user` (`activity_id`,`customer_id`) USING BTREE,
    ->   KEY `idx_activity` (`activity_id`,`point`) USING BTREE
    -> ) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8mb4 COMMENT='积分';
Query OK, 0 rows affected (0.01 sec)

2、插入数据,表中数据内容如下:
MySQL与MariaDB对子查询中order by的处理的差异

3、执行更新操作

wjq@118.89.xxx.xxx [wjqdb]>UPDATE points AS p,
    -> (SELECT @a:=@a+1 AS ranks, a.id as ids FROM points AS a,(SELECT @a:=0) r
    -> WHERE a.activity_id = 7241 AND a.point > 0 ORDER BY a.point DESC, a.id ASC) AS b
    -> SET p.ranking = ranks WHERE p.id = b.ids;
Query OK, 4 rows affected (0.00 sec)
Rows matched: 4  Changed: 4  Warnings: 0

4、验证更新以后的结果

MySQL与MariaDB对子查询中order by的处理的差异

通过上述的查看结果可以发现:

和论坛中发帖者的结果是一样的,这也是发帖者所期望的结果;

 

但是相同的操作,难道在mysql数据库就不行了吗?结果就不一样了?这么神奇吗?下面就在MYSQL环境测试一下;

 

MYSQL数据库

1、创建测试表

root@10.105.54.118 [wjq]>CREATE TABLE `points` (
    ->   `id` int(10) unsigned NOT NULL AUTO_INCREMENT COMMENT 'ID',
    ->   `activity_id` int(10) unsigned NOT NULL DEFAULT 0 COMMENT '项目',
    ->   `customer_id` int(10) NOT NULL DEFAULT 0 COMMENT '用户',
    ->   `point` int(10) NOT NULL DEFAULT 0 COMMENT '积分值',
    ->   `ranking` int(10) unsigned NOT NULL DEFAULT 0 COMMENT '当前排行',
    ->   `create_time` int(10) unsigned NOT NULL DEFAULT 0 COMMENT '创建时间',
    ->   `update_time` timestamp NOT NULL DEFAULT current_timestamp() ON UPDATE current_timestamp() COMMENT '最后更新时间',
    ->   PRIMARY KEY (`id`) USING BTREE,
    ->   UNIQUE KEY `uni_activity_user` (`activity_id`,`customer_id`) USING BTREE,
    ->   KEY `idx_activity` (`activity_id`,`point`) USING BTREE
    -> ) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8mb4 COMMENT='积分';
Query OK, 0 rows affected (0.00 sec)

2、插入数据,表中数据内容如下:

MySQL与MariaDB对子查询中order by的处理的差异

3、执行更新操作

root@10.105.54.118 [wjq]>UPDATE points AS p,
    -> (SELECT @a:=@a+1 AS ranks, a.id as ids FROM points AS a,(SELECT @a:=0) r
    -> WHERE a.activity_id = 7241 AND a.point > 0 ORDER BY a.point DESC, a.id ASC) AS b
    -> SET p.ranking = ranks WHERE p.id = b.ids;
Query OK, 4 rows affected (0.00 sec)
Rows matched: 4  Changed: 4  Warnings: 0

4、验证更新以后的结果

MySQL与MariaDB对子查询中order by的处理的差异

通过上述的查看结果可以发现:

相同的操作在MariaDB和MYSQL环境查询出来的结果是不一样的,这是为什么呢?

论坛看有人回复说是order by在MariaDB和MYSQL的处理方式是不一样的;具体是怎么不一样的呢?那就查看官方文档的说明:

分别查看了一下MYSQL和MariaDB的官方文档关于

MYSQL数据库关于order by的官方说明:

https://dev.mysql.com/doc/refman/5.7/en/order-by-optimization.html

MariaDB数据库关于order by的官方说明:

https://mariadb.com/kb/en/library/order-by/

https://mariadb.com/kb/en/library/why-is-order-by-in-a-from-subquery-ignored/

在MariaDB官方说明中找到如下的说明:
Query with ORDER BY in a FROM subquery produces unordered result. Is this a bug? Below is an example of this:
SELECT field1, field2 FROM ( SELECT field1, field2 FROM table1 ORDER BY field2 ) alias

returns a result set that is not necessarily ordered by field2. This is not a bug.
A “table” (and subquery in the FROM clause too) is – according to the SQL standard – an unordered set of rows. Rows in a table (or in a subquery in the FROM clause) do not come in any specific order. That’s why the optimizer can ignore the ORDER BY clause that you have specified. In fact, the SQL standard does not even allow the ORDER BY clause to appear in this subquery (we allow it, because ORDER BY … LIMIT … changes the result, the set of rows, not only their order).
You need to treat the subquery in the FROM clause, as a set of rows in some unspecified and undefined order, and put the ORDER BY on the top-level SELECT.

通过对比MYSQL和MariaDB的官方文档的说明,得出如下的结论:

MySQL与MariaDB对子查询语句当中的order by的处理方法不同。MySQL会去执行内层查询的排序子句,但是MariaDB会将这个order by忽略掉,除非在内层查询语句中不仅有order by,还有limit子句,那么这时这个order by是不会被MariaDB忽略的。

 

那么针对上述实际的问题要怎么解决呢?因为子查询中确实没有使用到limit,那我加上limit是否就会结果不一样呢?大家可以自己实验一下;但是反过来想一下,我的查询结果是未知的,如果使用limit去做限制,在实际的使用中不太现实,那要怎么办呢?只能改写SQL语句了,还能咋办呢?

通过分析:很明显在操作update的时候就出现了问题,也就是说在update中select查询出来的结果就有问题了,那update之后结果就有问题了,那再次查询结果肯定无法满足需求了;下面就是我通过实验针对update语句做了改写,改写之后再次查询就没有问题了;

改写SQL语句:

root@10.105.54.118 [wjq]>UPDATE points AS p,
    -> (SELECT * FROM
    -> (SELECT @a:=@a+1 AS ranks, a.id AS ids, a.point FROM points AS a,(SELECT @a := 0) r
    -> WHERE a.activity_id = 7241 AND a.point > 0 ORDER BY a.point DESC, a.id ASC) s ) AS b
    -> SET p.ranking = b.ranks WHERE p.id = b.ids;
Query OK, 4 rows affected (0.00 sec)
Rows matched: 4  Changed: 4  Warnings: 0

改写SQL语句之后,再次执行查询,这时候就和在MariaDB中的查询结果一样了;

MySQL与MariaDB对子查询中order by的处理的差异

完美解决,可喜可贺!

MySQL与MariaDB对子查询中order by的处理的差异


如果您觉得本站对你有帮助,那么可以收藏和推荐本站,帮助本站更好地发展,在此谢过各位网友的支持。
转载请注明原文链接:MySQL与MariaDB对子查询中order by的处理的差异
喜欢 (3)
SEian.G
关于作者:
用心去记录工作,用心去感受生活,用心去学着成长;座右铭:苦练七十二变,笑对八十一难
发表我的评论
取消评论

表情 贴图 加粗 删除线 居中 斜体 签到

Hi,您需要填写昵称和邮箱!

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址
(2)个小伙伴在吐槽
  1. 学习了,感谢分享
    dickyuan2019-02-28 21:04 回复 Windows 7 | Chrome 69.0.3497.100
    • SEian.G
      感谢支持 :mrgreen:
      SEian.G2019-02-28 21:19 回复 Windows 7 | Chrome 69.0.3497.100