【发布时间】:2011-04-11 21:57:41
【问题描述】:
truncate ->这会重置整个表,有没有办法通过 truncate 来重置特定的记录/检查条件。
例如:我想重置所有数据并在表格中保留最后 30 天。
谢谢。
【问题讨论】:
-
实际上,如果表被分割成分区,你可以只截断选定的分区,因此不会抽出整个表。
truncate ->这会重置整个表,有没有办法通过 truncate 来重置特定的记录/检查条件。
例如:我想重置所有数据并在表格中保留最后 30 天。
谢谢。
【问题讨论】:
不,TRUNCATE 是全部或全部。您可以使用DELETE FROM <table> WHERE <conditions>,但这会失去TRUNCATE 的速度优势。
【讨论】:
简短的回答是否:MySQL 确实不允许您在TRUNCATE 语句中添加WHERE 子句。这是MySQL's documentation 关于TRUNCATE 声明的内容。
但好消息是,您可以(在某种程度上)绕过这个限制。
使用DELETE的简单、安全、干净但缓慢的解决方案
首先,如果表足够小,只需使用DELETE语句即可(不得不提):
1. LOCK TABLE my_table WRITE;
2. DELETE FROM my_table WHERE my_date<DATE_SUB(NOW(), INTERVAL 1 MONTH);
3. UNLOCK TABLES;
LOCK 和 UNLOCK 语句不是强制性的,但它们会加快处理速度并避免潜在的死锁。
不幸的是,如果您的表很大,这将非常慢......并且由于您正在考虑使用TRUNCATE 语句,我想这是因为您的表很大。
所以这是使用TRUNCATE 语句解决您的问题的一种方法:
使用TRUNCATE的简单、快速但不安全的解决方案
1. CREATE TABLE my_table_backup AS
SELECT * FROM my_table WHERE my_date>=DATE_SUB(NOW(), INTERVAL 1 MONTH);
2. TRUNCATE my_table;
3. LOCK TABLE my_table WRITE, my_table_backup WRITE;
4. INSERT INTO my_table SELECT * FROM my_table_backup;
5. UNLOCK TABLES;
6. DROP TABLE my_table_backup;
不幸的是,如果其他进程同时在表中插入记录,这个解决方案有点不安全:
TRUNCATE 语句将AUTO-INCREMENT 计数器重置为零。因此,在第 2 步和第 3 步之间插入的任何记录的 ID 都将低于旧 ID,甚至可能与在第 4 步插入的 ID 冲突(请注意,AUTO-INCREMENT 计数器将在第 4 步之后恢复到正确的值) .很遗憾,无法锁定表并截断它。但是我们可以(以某种方式)使用RENAME 解决那个限制。
使用TRUNCATE的半简单、快速、安全但嘈杂的解决方案
1. RENAME TABLE my_table TO my_table_work;
2. CREATE TABLE my_table_backup AS
SELECT * FROM my_table_work WHERE my_date>DATE_SUB(NOW(), INTERVAL 1 MONTH);
3. TRUNCATE my_table_work;
4. LOCK TABLE my_table_work WRITE, my_table_backup WRITE;
5. INSERT INTO my_table_work SELECT * FROM my_table_backup;
6. UNLOCK TABLES;
7. RENAME TABLE my_table_work TO my_table;
8. DROP TABLE my_table_backup;
这应该是完全安全且相当快的。唯一的问题是其他进程会看到表my_table 消失几秒钟。这可能会导致错误显示在各处的日志中。所以这是一个安全的解决方案,但它“嘈杂”。
免责声明:我不是 MySQL 专家,所以这些解决方案实际上可能很糟糕。我能提供的唯一保证是它们对我很好。如果有专家可以对这些解决方案发表评论,我将不胜感激。
【讨论】:
作为对您问题的回答: “我想重置所有数据并在表格中保留最后 30 天。”
您可以创建一个事件。检查https://dev.mysql.com/doc/refman/5.7/en/event-scheduler.html
例如:
CREATE EVENT DeleteExpiredLog
ON SCHEDULE EVERY 1 DAY
DO
DELETE FROM log WHERE date < DATE_SUB(NOW(), INTERVAL 30 DAY);
将在您的表中运行每日清理,保持最近 30 天的数据可用
【讨论】:
您可以使用 datapump 使用查询子句简单地导出表,然后使用 table_exists_action=replace 子句将其导入回来。它会删除并重新创建您的表,并且花费的时间非常少。请在实施前阅读。
【讨论】: