Mysql在5.7.x中选择不同的子查询与查询

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Mysql在5.7.x中选择不同的子查询与查询相关的知识,希望对你有一定的参考价值。

让我先说一下,我在这里描述的内容在mysql 5.6.x及更低版本中运行得很好。现在我们尝试更新到mysql 5.7并查找此UPDATE语句的问题。

我们有一个看起来像这样的表:

imagefile
----------
id      int
itemId  int
...
sequenceNumber int
updatedDate    date

在我们的应用程序中,用户必须在Item中重新排序imageFiles。我们这样做的SQL看起来像这样:

UPDATE imageFile f1 
  JOIN ( 
        SELECT f2.id, (@row:=@row+1) rowNum 
          FROM imageFile f2, (SELECT @row:=0) dm 
         WHERE f2.itemId = 8035323
         ORDER BY f2.sequenceNumber, f2.updatedDate 
        ) rs ON f1.id = rs.id 
SET f1.sequenceNumber = rs.rowNum;

如果我只将select部分作为独立查询运行,它会产生以下结果:

SELECT f2.id, f2.sequenceNumber, sqNum (@row:=@row+1) rowNum, updatedDate 
  FROM imageFile f2, (SELECT @row:=0) dm 
 WHERE f2.itemId = 8035323
 ORDER BY f2.sequenceNumber, f2.updatedDate;

 id   sqNum   rowNum   updatedDate
| 9 |   1   |   1   |2018-04-16 18:39:12
| 8 |   2   |   2   |2018-04-16 18:38:42
| 7 |   3   |   3   |2018-04-16 18:37:03
| 6 |   4   |   4   |2018-04-16 18:37:28
| 5 |   5   |   5   |2018-04-16 18:36:37
| 4 |   6   |   6   |2018-04-16 18:38:16
| 3 |   7   |   7   |2017-09-12 16:59:20

哪个是正确的,正是我所期望的...在我使用SELECT作为子查询/ join运行UPDATE后,我得到了这个:

 id   sqNum  rowNum   updatedDate
| 3 |   1   |   1   |2017-09-12 16:59:20
| 4 |   2   |   2   |2018-04-16 18:38:16
| 5 |   3   |   3   |2018-04-16 18:36:37
| 6 |   4   |   4   |2018-04-16 18:37:28
| 7 |   5   |   5   |2018-04-16 18:37:03
| 8 |   6   |   6   |2018-04-16 18:38:42
| 9 |   7   |   7   |2018-04-16 18:39:12

这是完全错误的,似乎没有遵循我告诉它的任何顺序。显然在新版本的mysql中有些变化。当我在每个版本中为该查询执行EXPLAIN时,它也是不同的......

5.6.34

id  select_type table   type    possible keys   key key length  ref rows    extra
1   PRIMARY <derived2>  ALL NULL    NULL    NULL    NULL    35  NULL
1   PRIMARY i1  eq_ref  PRIMARY PRIMARY 4   rs.id   1   NULL
2   DERIVED <derived3>  system  NULL    NULL    NULL    NULL    1   Using filesort
2   DERIVED i2  ref uc_ItemNumber, in_workspaceId   uc_ItemNumber   4   const   35  Using where
3   DERIVED NULL    NULL    NULL    NULL    NULL    NULL    NULL    No tables used

5.7.18

id  select_type table   type    possible_keys   key key_len ref rows    extra
1   PRIMARY <derived2>  ALL                 35  
1   UPDATE  i1  eq_ref  PRIMARY PRIMARY 4   rs.id   1   
2   DERIVED i2  ref uc_ItemNumber, in_workspaceId   uc_ItemNumber   4   const   35  Using temporary; Using filesort
2   DERIVED <derived3>  ALL                 1   Using join buffer (Block Nested Loop)
3   DERIVED                             No tables used

我的问题是如何让这回到以前/期望的行为?

答案

我似乎记得不应该使用/依赖MySQL DML语句的会话变量。但好消息是我们可以在没有会话变量的情况下重写您的查询:

UPDATE imageFile f1 
INNER JOIN
( 
    SELECT
        f2.id, 
        (SELECT COUNT(*) 
         FROM imageFile t
     WHERE t.itemId = 8035323 AND
           (t.sequenceNumber < f2.sequenceNumber OR
            t.sequenceNumber = f2.sequenceNumber AND
            (t.updatedDate < f2.updatedDate OR
            (t.updatedDate = f2.updatedDate AND t.id < f2.id)))) rowNum
    FROM imageFile f2
    WHERE f2.itemId = 8035323
) rs
    ON f1.id = rs.id 
SET f1.sequenceNumber = rs.rowNum;

以上是关于Mysql在5.7.x中选择不同的子查询与查询的主要内容,如果未能解决你的问题,请参考以下文章

mysql中的子查询将一列用于两个不同的结果

MySQL 的子查询和left join的比较,啥时候用子查询效率高,啥时候用left join效率高?

在 MYSQL 的子查询中使用 LIMIT 关键字的替代方法

SQL查询以选择在同一列中具有不同值的子记录的父级

那个mysql 子查询和连接查询 一般常用哪个 谁效率高些

mysql中主查询和子查询关系是啥?