MySQL:在事务中截断表?

时间:2011-05-12 01:21:42

标签: mysql transactions truncate

我有一个InnoDB表需要每隔十分钟在60k到200k记录的任何地方重新填充。到目前为止,我们的方法如下:

  1. 关闭自动提交
  2. 截断表格
  3. 执行选择查询&额外的计算(使用PHP)
  4. 插入新记录
  5. 提交
  6. 执行截断操作后,数据会立即删除,并且不再可用于用户界面。对于我们的用户来说,这非常令人不安,即使在大约30秒左右的时间内脚本遇到了Commit操作并且表格被重新填充。

    我想也许我可以在事务中包装整个操作包括 Truncate,这可能会减少表空出现的时间长度给用户。所以我将SET AUTOCOMMIT=0更改为START TRANSCATION

    Yikes!这与预期的效果相反!现在TRUNCATE操作仍然发生在脚本的开头,但实际执行事务中的INSERT操作需要更长,所以到COMMIT时{1}}操作发生,表格中的数据再次可用,几乎 十分钟!

    可能导致这种情况的原因是什么?说实话,我根本没想到会有任何改变,因为我认为启动交易基本上只会关闭Autocommit吗?

4 个答案:

答案 0 :(得分:53)

实现此目标的更好方法可能是将数据插入新表,然后在两个表上使用rename以交换它们。单个重命名是交换所需的全部内容,这是一个原子操作,这意味着除了显示的新数据外,用户甚至无法检测到它发生了。然后,您可以截断/删除旧数据。

答案 1 :(得分:53)

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

根据此URL,从MySQL 5.1.32开始,TRUNCATE TABLE是DDL而非DML,如DELETE。这意味着TRUNCATE TABLE将在事务块中间导致隐式COMMIT。因此,在需要清空的表格上使用DELETE FROM而不是TRUNCATE TABLE

甚至可以回滚DELETE FROM tblname;。回滚可能需要一段时间,因此请确保InnoDB已正确调整以处理此类回滚可能性的事务时间。

答案 2 :(得分:0)

根据你的描述,我无法解释你的时差。我唯一想到的是你实际上并没有将插入包装到一个事务中,而是循环它。

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

答案 3 :(得分:0)

TRUNCATE表示COMMIT,因此该事务不是ACID事务。上面已经指出了。

-

我在MySQL中使用您的方法来通过电子邮件地址模拟两个表的OUTER JOIN。结果留在表中,我以后可以快速INNER JOIN

您的方法已经具有过时的数据(因为您需要DELETE)。因此,这是另一种方法,该方法也使用过时的数据,但完全放弃了交易。减少锁定FTW。

只需INSERT... ON DUPLICATE KEY UPDATE并标记一个“更新时间”。在脚本结尾处,DELETE带有旧的“更新时间”的任何内容。

相关问题