InnoDB为什么不读取或不正确写入计数?

时间:2014-04-07 12:00:03

标签: mysql transactions innodb

我的任务是维护一个处理"批次"有"记录"。它们使用InnoDB表存储在MySQL中,log.batch_id外键将每个批次与其日志链接起来。

我最近不得不优化某些操作的性能,其中一个操作涉及获取批次列表以及每个操作的日志计数。此操作过去实现为LEFT JOINbatch.id分组,但性能不可接受,因此我转换为非规范化状态,每个批次保持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等于零的批处理(即创建时的初始值是什么),同时日志在数据库中显示就好了。

发生了什么?我不明白以上可以正确更新日志计数的可能性。我已经考虑过重构一下,以便将SELECT COUNT(*) / UPDATE batch对变成单个UPDATE ... SELECT,但这看起来并没有帮助。

可能相关的其他信息:

  • 有效的事务隔离级别是REPEATABLE READ。
  • 只有几千个日志的批次才会出现这个问题,但即使这样,它也很少发生。

1 个答案:

答案 0 :(得分:0)

如果您使用的是MySQL 5.5或5.6 然后可能由于以下原因而发生:

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