【问题标题】:Truncate with condition有条件截断
【发布时间】:2011-04-11 21:57:41
【问题描述】:

truncate ->这会重置整个表,有没有办法通过 truncate 来重置特定的记录/检查条件。

例如:我想重置所有数据并在表格中保留最后 30 天。

谢谢。

【问题讨论】:

  • 实际上,如果表被分割成分区,你可以只截断选定的分区,因此不会抽出整个表。

标签: sql mysql truncate


【解决方案1】:

不,TRUNCATE 是全部或全部。您可以使用DELETE FROM <table> WHERE <conditions>,但这会失去TRUNCATE 的速度优势。

【讨论】:

  • 谢谢,假设这种情况,我如何以优化的方式保留过去 10 天的数据并删除其余的数据(例如表有 1000 万条记录)。
  • TRUNCATE的速度是因为它不写入日志
  • 除了速度截断还释放磁盘空间,但删除保留磁盘空间。
【解决方案2】:

简短的回答是: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;

LOCKUNLOCK 语句不是强制性的,但它们会加快处理速度并避免潜在的死锁。

不幸的是,如果您的表很大,这将非常慢......并且由于您正在考虑使用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;

不幸的是,如果其他进程同时在表中插入记录,这个解决方案有点不安全:

  • 在步骤 1 和 2 之间插入的任何记录都将丢失
  • 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 专家,所以这些解决方案实际上可能很糟糕。我能提供的唯一保证是它们对我很好。如果有专家可以对这些解决方案发表评论,我将不胜感激。

【讨论】:

  • 很好的答案和很好的解决限制的方法。谢谢。
【解决方案3】:

作为对您问题的回答: “我想重置所有数据并在表格中保留最后 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 天的数据可用

【讨论】:

    【解决方案4】:

    您可以使用 datapump 使用查询子句简单地导出表,然后使用 table_exists_action=replace 子句将其导入回来。它会删除并重新创建您的表,并且花费的时间非常少。请在实施前阅读。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2023-03-21
      • 1970-01-01
      • 1970-01-01
      • 2022-01-07
      • 2020-03-27
      • 1970-01-01
      • 2017-06-30
      • 1970-01-01
      相关资源
      最近更新 更多