web-dev-qa-db-ja.com

条件付き切り捨て

truncate->これはテーブル全体をリセットします。truncateを介して特定のレコード/チェック条件をリセットする方法があります。

例:すべてのデータをリセットし、過去30日間をテーブル内に保持します。

ありがとう。

36
Sharpeye500

いいえ、TRUNCATEはすべてまたはゼロです。 DELETE FROM <table> WHERE <conditions>しかし、これはTRUNCATEの速度の利点を失います。

57
ceejayoz

簡単な答えはno:MySQLはnotを使用してWHERE句をTRUNCATEステートメントに追加できます。 TRUNCATEステートメントに関する MySQLのドキュメント は次のとおりです。

しかし、良いニュースは、この制限を(ある程度)回避できることです。

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ステートメントを使用して問題を解決する1つの方法を次に示します。

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)。

残念ながら、テーブルをロックして切り捨てることはできません。しかし、(とにかく)thatRENAMEを使用して制限を回避できます。

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の専門家ではないので、これらのソリューションは実際には安っぽいかもしれません。私が提供できる唯一の保証は、彼らが私のためにうまく働くということです。これらのソリューションについて専門家がコメントできる場合は、感謝します。

28
MiniQuark

あなたの質問への回答として:「すべてのデータをリセットし、過去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日間のデータを利用可能にします

1
Felipe Torres

Datapumpを使用してクエリ句でテーブルをエクスポートし、table_exists_action = replace句でインポートして戻すことができます。テーブルが削除されてテーブルが再作成され、時間がかかりません。実装する前にそれについて読んでください。

0
user4603856