MySQL/InnoDB和长时间运行的查询

MySQL/InnoDB和长时间运行的查询,mysql,sql,innodb,Mysql,Sql,Innodb,在使用myisam引擎运行查询时,因为它不是事务性的,所以长查询(据我所知)不会影响其他查询的数据 在InnoDB中,它警告的一件事是避免长查询。当InnoDB快照时,它会快照所有内容吗 我问这个问题的原因是:不管出于什么原因,一个查询都会比正常情况下花费更长的时间,最终会回滚。同时,还有200名其他用户更新或将行插入数据库。当长查询回滚时,它是否也会删除其他用户所做的更新/插入?或者,涉及其他用户的行是否安全,除非它们与回滚的行交叉?您的查询是否影响并发性与查询类型有关。拥有许多读取查询不会影

在使用myisam引擎运行查询时,因为它不是事务性的,所以长查询(据我所知)不会影响其他查询的数据

在InnoDB中,它警告的一件事是避免长查询。当InnoDB快照时,它会快照所有内容吗


我问这个问题的原因是:不管出于什么原因,一个查询都会比正常情况下花费更长的时间,最终会回滚。同时,还有200名其他用户更新或将行插入数据库。当长查询回滚时,它是否也会删除其他用户所做的更新/插入?或者,涉及其他用户的行是否安全,除非它们与回滚的行交叉?

您的查询是否影响并发性与查询类型有关。拥有许多读取查询不会影响MyISAM或InnoDB中的并发性(除了性能问题)

插入(使用InnoDB插入索引的末尾,或使用MyISAM插入表的末尾)也不会影响并发性

然而,一旦有了更新查询,InnoDB中的行就会被锁定,而使用MyISAM,整个表都会被写锁定。当您尝试更新具有写锁的记录(或表)时,必须等到锁释放后才能继续。在MyISAM中,更新是在读取之前提供的,因此您必须等待更新得到处理

MyISAM的性能更高,因为表锁比记录锁快(尽管记录锁很快)。但是,当您开始进行大量更新时,通常首选InnoDB,因为不同的用户通常不太可能争夺相同的记录。因此,使用InnoDB,由于记录级锁定(而不是表锁),许多用户可以并行工作,而不会相互影响太多

更不用说InnoDB带来的完全符合ACID的好处、外键约束的强制执行以及聚集索引的速度

快照(日志项)的保存时间足以完成当前事务,如果回滚或提交快照,则会将其丢弃。事务运行的时间越长,就越有可能发生其他更新,这会增加回滚所需的日志条目数

由于锁定,不会出现“交叉”。当对相同记录存在写入争用时,一个用户必须等待另一个用户提交或回滚


你可以阅读更多有关的内容。

首先,我认为作为背景阅读这个答案会很有用

InnoDB实现了MVCC,这意味着它可以对常规
SELECT
使用非锁定读取。这不需要创建“快照”,事实上InnoDB没有任何真正的快照对象概念。相反,数据库中的每个记录都会跟踪自己的版本号,并维护一个指向“撤消日志”记录(可能存在,也可能不存在)的“滚动指针”,该记录会将行修改为其以前的版本。如果需要记录的旧版本,则会读取当前版本,并遵循这些滚动指针,并应用撤消记录,直到生成足够旧的记录版本

通常,系统会不断清理这些撤销日志,并重新使用它们占用的空间

任何时候出现任何长时间运行的事务(注意,不一定是单个查询),都必须保留(不清除)撤消日志,以便充分重新创建所有记录的足够旧的版本以满足该事务。在一个非常繁忙的系统中,这些撤销日志可以非常快地累积起来,从而消耗千兆字节的空间。此外,如果特定的单个记录经常被修改,则将该记录恢复到足够旧的版本以满足查询可能需要很多撤消日志应用程序(数千)

这就是为什么“长时间运行的查询”代价高昂,并且令人不快的原因。它们将增加在系统表空间中保留撤消日志的磁盘空间消耗,并且由于撤消日志记录应用程序在读取时还原行版本,它们的性能将很差


一些数据库实现了可消耗的最大撤消日志空间,一旦达到该限制,它们就会开始丢弃旧的撤消日志记录并使正在运行的事务无效。这会向用户生成“快照太旧”错误消息。InnoDB没有这样的限制,并且允许无限期累积。

快照本身没有物理显示,只有更新的行的旧版本。长时间运行的事务禁止对这些旧行进行垃圾收集。即,如果任何未完成的事务仍需要“查看”处于该事务启动时状态的数据库(且该事务可重复读取),则无法清除完成其数据状态视图所需的旧行版本。事务越长,回滚段中累积的数据越多,假设更新继续发生。我更新了答案。如果还有不准确的地方,请告诉我。是的,看起来好多了。