我有一个InnoDB表需要每隔十分钟在60k到200k记录的任何地方重新填充。到目前为止,我们的方法如下:
执行截断操作后,数据会立即删除,并且不再可用于用户界面。对于我们的用户来说,这非常令人不安,即使在大约30秒左右的时间内脚本遇到了Commit操作并且表格被重新填充。
我想也许我可以在事务中包装整个操作包括 Truncate
,这可能会减少表空出现的时间长度给用户。所以我将SET AUTOCOMMIT=0
更改为START TRANSCATION
。
Yikes!这与预期的效果相反!现在TRUNCATE
操作仍然发生在脚本的开头,但实际执行事务中的INSERT
操作需要更长,所以到COMMIT
时{1}}操作发生,表格中的数据再次可用,几乎 十分钟!
可能导致这种情况的原因是什么?说实话,我根本没想到会有任何改变,因为我认为启动交易基本上只会关闭Autocommit
吗?
答案 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
带有旧的“更新时间”的任何内容。