mysql - 为什么 InnoDB 无法正确读取或写入计数?

标签 mysql transactions innodb

我的任务是维护一个处理具有“日志”的“批处理”的应用程序。这些数据使用 InnoDB 表存储在 MySQL 中,并使用 log.batch_id 外键将每个批处理与其日志链接起来。

我最近必须优化某些操作的性能,其中之一涉及获取批处理列表以及每个批处理的日志计数。此操作过去被实现为按 batch.id 分组的 LEFT JOIN,但性能 Not Acceptable ,因此我转换为保留 cached_log_count< 的非规范化状态 每批的值。

由于应用程序如何处理其业务,此缓存计数仅在创建后不久为每个批处理更新一次。伪代码如下:

# there are no logs at all for batch id = 42 at this point
$batch = SELECT * FROM batch WHERE id = 42
BEGIN
    FOR (EACH LOG)
        INSERT INTO log (batch.id, ...) VALUES 42, ...
        # error checking elided
    END FOR
    $logCount = SELECT COUNT(*) FROM log WHERE batch.id = 42
    UPDATE batch SET cached_log_count = $logCount WHERE id = 42
COMMIT

我希望上面的内容能够填充 log 表并正确设置关联批处理的 cached_log_count大多数时候确实如此会发生什么。然而,我经常会得到一个 cached_log_count 等于 0 的批处理(即创建时的初始值),同时日志在数据库中显示得很好。

发生什么事了?我不明白上面的内容怎么可能总是正确更新日志计数。我考虑过进行一些重构,以便将 SELECT COUNT(*)/UPDATE batch 对转换为单个 UPDATE ... SELECT,但这看起来没有帮助。

可能相关的其他信息:

  • 有效的事务隔离级别是 REPEATABLE READ。
  • 该问题似乎仅在具有数千个日志的批处理中出现,但即使如此,也很少发生。

最佳答案

如果您使用的是 MySQL 5.5 或 5.6 那么出现这种情况可能是由于以下原因:

  • 在某些情况下,优化器可能会优化掉用户定义的变量,从而阻止它们执行您想要的操作。
  • 分配的顺序,甚至分配的时间,都可能是不确定的,并且取决于优化器选择的查询计划。结果可能会非常令人困惑,稍后您将会看到。
  • := 赋值运算符的优先级低于任何其他运算符,因此必须小心地显式添加括号。

关于mysql - 为什么 InnoDB 无法正确读取或写入计数?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/22911808/

相关文章:

java - 如何在 java、MySQL 和 Tomcat 6 中使用连接池

ios7 - 如果 PayPal 余额为 0.00 美元,则在 PayPal 实时交易中出现问题

mysql - Node.js mysql 事务

ruby-on-rails - 在 Ctrl+C 中断的情况下,如何在 Rake 任务中使用 ActiveRecord 事务进行回滚

MySQL:如何更新所有现有条目的自动增量?

php - 突出显示字符串中的多个搜索词

mysql - 计算每行出现多少次不同的单词

MySql - 忽略选择具有特定元素的查询中的数据

MySQL InnoDB 自愿事务成为死锁受害者

MySQL 5.7 alter table DDL 语句锁定,但应允许并发 DML