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

时间:2014-01-09 20:42:18

标签: mysql sql innodb

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

在InnoDB中,它警告的一件事是避免长时间的查询。当InnoDB快照时,是否会快照一切?

我之所以这么说是因为:无论出于什么原因,查询都会花费比平时更长的时间并最终回滚。同时,其他200个用户已将行更新或插入数据库。当长查询回滚时,它是否还删除其他用户所做的更新/插入?或者是涉及其他用户安全的行,除非他们越过回滚的那个?

2 个答案:

答案 0 :(得分:5)

首先,我认为以multi-version concurrency control (MVCC)作为背景来阅读这个答案是有用的。

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

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

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

这就是让“长时间运行的查询”变得昂贵且令人不悦的原因。它们会增加磁盘空间消耗,以便将撤消日志保留在系统表空间中,并且由于撤消日志记录应用程序在读取时恢复行版本,它们将表现不佳。

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

答案 1 :(得分:2)

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

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

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

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

更不用说InnoDB获得完全ACID合规性的好处,外键约束的执行以及聚簇索引的速度。

快照(日志条目)保持足够长的时间来完成当前事务,如果它们被回滚或提交则被丢弃。事务运行的时间越长,其他更新发生的可能性就越大,这会增加回滚所需的日志条目数。

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

您可以阅读有关The InnoDB Transaction Model and Locking的更多信息。