相同的查询在重复执行时返回不同的值

Posted

技术标签:

【中文标题】相同的查询在重复执行时返回不同的值【英文标题】:Same query returns different values on repeated execution 【发布时间】:2019-03-04 04:49:47 【问题描述】:

正在使用的数据库:5.6(我不能使用来自 mysql 8 的 LAG 函数)

我在mysql中有如下表结构

book_id     | Version      | Rating | Price 
varchar(25) | Decimal(10,2)| int    | Decimal(10,2)

我有一个显示两个图表的网页。

在第一个图表中,我将显示用于评分的书籍数量(评分仅从 1 到 4),但仅显示最新版本。 Query1

在第二张图表中,我将显示价格范围内的书籍数量,但仅显示最新版本。 Query2

每次加载或刷新网页时,这两个查询都会一个接一个地运行。尽管数据保持不变,但有时对于同一个查询,我会得到不同的结果。

我有以下两个几乎相同的查询

QUERY1

SELECT  
       SUM(CASE WHEN rating=1 THEN 1 ELSE 0) AS rating1,
       SUM(CASE WHEN rating=2 THEN 1 ELSE 0) AS rating2,
       SUM(CASE WHEN rating=3 THEN 1 ELSE 0) AS rating3,
       SUM(CASE WHEN rating=4 THEN 1 ELSE 0) AS rating4
FROM (
       SELECT rating, row_number
       FROM (
              SELECT rating, 
                     @num:=IF(@group:=book_id, @num+1, 1) row_number,
                     @group:=book_id bi
              FROM book_database
              ORDER BY book_id, version DESC
             ) book
      HAVING book.row_number = 1
    ) book

QUERY2

SELECT  
       SUM(CASE WHEN price <= 1000 THEN 1 ELSE 0) AS cheap,
       SUM(CASE WHEN price >1000 THEN 1 ELSE 0) AS costly
FROM (
       SELECT price, row_number
       FROM (
              SELECT price, 
                     @num:=IF(@group:=book_id, @num+1, 1) row_number,
                     @group:=book_id bi
              FROM book_database
              ORDER BY book_id, version DESC
             ) book
      HAVING book.row_number = 1
    ) book

我的网页中有多个屏幕,并且有多个查询,但大多数都使用相同的逻辑。基本上我会查询任何一本书的最新版本,因此我使用嵌套查询。

在某些情况下,当相同的查询在同一数据集上运行多次时,我得到的结果与预期不同。

我的查询是否正确? 变量的使用是否会导致此问题? 由于多个查询是并行运行的(尽管在不同的数据库连接中)变量的使用是可疑的?

【问题讨论】:

这就是在子查询中使用ORDER BY 子句的美妙之处。 MySQL 可能会在需要时选择忽略它! 你能详细说明一下吗 见mysqlserverteam.com/… 我通读了这篇文章......它不适用于这种情况 还有什么可以解释得到不同的结果?关键是 的嵌套顺序可以被 忽略。我想您可以将HAVING 替换为WHERE... 这应该会产生相同的结果并消除不必要的GROUP BY 并且可能会产生正确的结果。 【参考方案1】:

您对变量的使用不正确。 MySQL 不保证SELECT 子句中表达式的求值顺序,因此您应该同时设置所有变量。

例如,第一个查询应该看起来更像这样:

SELECT SUM( rating = 1 ) AS rating1,
       SUM( rating = 2 ) AS rating2,
       SUM( rating = 3 ) AS rating3,
       SUM( rating = 4 ) AS rating4
FROM (SELECT rating, book_id,
             (@rn := if(@b = book_id, @rn + 1,
                        if(@b := book_id, 1, 1)
                       )
             ) as rn
      FROM (SELECT rating, book_id, version
            FROM book_database
            ORDER BY book_id, version DESC
           ) book CROSS JOIN
           (SELECT @rn := 0, @b := -1) params
    ) book
WHERE rn = 1;

重要的部分是涉及变量的部分。我还简化了其他一些逻辑。

但是,你不需要变量:

SELECT SUM( rating = 1 ) AS rating1,
       SUM( rating = 2 ) AS rating2,
       SUM( rating = 3 ) AS rating3,
       SUM( rating = 4 ) AS rating4
FROM book_database b
WHERE b.version = (SELECT MAX(b2.version)
                   FROM book_database b2
                   WHERE b2.book_id = b.book_id
                  );

book_database(book_id, version) 上有索引,这应该比使用变量的版本更快。

【讨论】:

以上是关于相同的查询在重复执行时返回不同的值的主要内容,如果未能解决你的问题,请参考以下文章

如何在cfoutput中显示不同的值

如何实现 IEqualityComparer 以返回不同的值?

如何确保两行不具有相同的值[重复]

数据库:去重和查询重复数据

LINQ 和 SQL 中看似等效的查询返回不同的结果 [重复]

类变量对于不同的实例具有不同的值[重复]