2011-05-12 43 views
26

我有一个InnoDB表,需要每10分钟内从60k到200k记录中的任何地方重新填充。我们的方法到现在为止一直如下:MySQL:在事务中截断表?

  1. 关闭自动提交
  2. 截断表
  3. 执行SELECT查询&额外的计算(使用PHP)
  4. 插入新记录
  5. 提交

虽然通过截断操作执行后,数据立即删除,并且没有lon ger可从用户界面获得。对我们的用户来说,这非常令人不安,即使在大约30秒左右的时间内,脚本遇到提交操作并且表被重新填充。

我想也许我可以在整个交易中将整个操作包括在内,包括 Truncate,并且这可能会减少表格在用户期间显示为空的时间长度。所以我将“SET AUTOCOMMIT = 0”改为“START TRANSCATION”。

哎呀!这与期望的效果相反!现在TRUNCATE操作仍然发生在脚本的开头,但是在事务内部实际执行INSERT操作需要很长时间,因此在执行COMMIT操作并且表中的数据再次可用时,已经差不多十分钟!

什么可能导致此?实际上,我根本没有期望有任何改变,因为我的印象是,启动交易基本上只会关闭Autocommit?

回答

37

完成此操作的更好方法可能是将数据插入到新表中,然后在两个表上使用rename以交换它们。交换只需要一次重命名,这是一个原子操作,这意味着除了显示新数据外,用户甚至无法检测到它发生了。然后可以截断/删除旧数据。

+0

这是一个非常有趣的想法。我最初的直觉反应是表面感觉有点ha but,但实际上它们有一定的优雅简单性,它可​​以完美地解决我的问题。希望我自己想到了。 :) – 2011-05-13 01:32:39

+5

已经过去将近一年了,只是想跟进并提到这就是我们最终做的事情,它就像一个魅力。我们创建新表格,插入一大堆记录,并在更新完成后立即将它们交换出去 - 最终用户即时显示。再次感谢。 – 2012-02-22 00:13:59

+0

谢谢你。一直在用最好的方式来进行批量数据更新,而不需要将数据库关闭几秒钟。这是一个很好的解决方法。 – NickH 2013-06-29 18:47:22

0

从你的描述我不能真正解释你的时差。唯一想到的是,你实际上并没有将插入物换成一个事务,而是将其循环。

与SET AUTOCOMMIT = 0的关键区别在于,如果已经为0,则它​​不会执行任何操作,与START TRANSACTION一样,您将在当前事务中启动子事务。

44

http://dev.mysql.com/doc/refman/5.1/en/truncate-table.html

根据这个URL,例如MySQL 5.1.32的,TRUNCATE TABLE是DDL和DML不喜欢删除。这意味着TRUNCATE TABLE将导致在事务块的中间隐含COMMIT。因此,在需要清空而不是TRUNCATE TABLE的表格上使用DELETE FROM

即使DELETE FROM tblname;也可以回滚。可能需要一段时间才能回滚,因此请确保InnoDB已正确调整以处理事务处理时间以进行此类回滚。

+0

这是很棒的信息,罗兰多;我非常感谢澄清(和参考)!如果Kibbee没有给我这样一个非常简单的解决方案,我绝对会给你最好的。 – 2011-05-13 01:36:00

+4

@RolandoMySQLDBA请注意,'DELETE FROM table'和'TRUNCATE table'之间的区别并不仅仅在于执行时间。 'TRUNCATE'也将'AUTO_INCREMENT'值重置为1,但是'DELETE'不会。 – ANTARA 2014-03-24 15:43:56

+1

“,因此请确保InnoDB已妥善调整以处理交易时间以实现此类回滚可能性。”有关如何做到这一点的任何见解? – vcardillo 2015-03-31 04:34:05