94

私は最近、私が取り組んでいたサイトでバグを見つけて修正しました。これにより、テーブル内に何百万ものデータの重複行が発生し、それらがなくても非常に大きくなります (まだ数百万)。これらの重複行を簡単に見つけることができ、単一の削除クエリを実行してそれらをすべて削除できます。問題は、一度にこれほど多くの行を削除しようとすると、テーブルが長時間ロックされることです。これは、可能であれば回避したいと考えています。(テーブルをロックすることによって) サイトをダウンさせずに、これらの行を取り除くことができる唯一の方法は次のとおりです。

  1. 数千の小さな削除クエリをループで実行するスクリプトを作成します。これにより、理論的にはロックされたテーブルの問題を回避できます。これは、他のクエリがキューに入って削除の間に実行できるためです。ただし、それでもデータベースの負荷がかなり高くなり、実行に時間がかかります。
  2. テーブルの名前を変更し、既存のテーブルを再作成します (現在は空になります)。次に、名前が変更されたテーブルでクリーンアップを行います。新しいテーブルの名前を変更し、古いテーブルの名前を元に戻して、新しい行を名前を変更したテーブルにマージします。これにはかなり多くの手順が必要ですが、中断を最小限に抑えて作業を完了する必要があります。ここで唯一難しいのは、問題のテーブルがレポート テーブルであることです。名前を変更して空のテーブルを元の場所に配置すると、元の場所に戻すまですべての履歴レポートが消えてしまいます。さらに、格納されているデータの種類が原因で、マージ プロセスが少し面倒になる可能性があります。全体として、これは今のところ私の選択の可能性が高いです。

他の誰かが以前にこの問題を抱えていたかどうか、もしそうなら、サイトを停止せずに、できればユーザーへの中断を最小限に抑えて、どのように対処したのだろうか? 2 番目の方法、または別の同様の方法を使用する場合、夜遅くに実行し、翌朝早くマージを実行するようにスケジュールを設定し、事前にユーザーに知らせることができるので、大したことではありません。誰かがクリーンアップを行うためのより良い、またはより簡単な方法についてアイデアを持っているかどうかを確認しているだけです.

4

16 に答える 16

178
DELETE FROM `table`
WHERE (whatever criteria)
ORDER BY `id`
LIMIT 1000

影響を受ける行がゼロになるまで、洗浄、すすぎ、繰り返します。繰り返しの間に 1 秒か 3 秒スリープするスクリプトの場合かもしれません。

于 2009-08-23T16:40:51.390 に答える
10

以下は、一度に 1,000,000 件のレコードを削除します。

 for i in `seq 1 1000`; do 
     mysql  -e "select id from table_name where (condition) order by id desc limit 1000 " | sed 's;/|;;g' | awk '{if(NR>1)print "delete from table_name where id = ",$1,";" }' | mysql; 
 done

それらをグループ化して、IN (id1,id2,..idN) が難しすぎると確信している table_name を削除することができます

于 2016-04-13T18:57:24.073 に答える
8

また、これが二度と起こらないように、テーブルにいくつかの制約を追加することをお勧めします。1ショットあたり1000行の100万行は、スクリプトを1000回繰り返す必要があります。スクリプトが3.6秒ごとに1回実行される場合、1時間で完了します。心配ない。クライアントが気付くことはほとんどありません。

于 2009-08-23T16:50:42.900 に答える
2

優れたMaatkitユーティリティパッケージ(MySQL管理用のPerlスクリプトの束)のmk- archiverを使用します。Maatkitは、O'Reillyの「HighPerformanceMySQL」の著者であるBaronSchwartzの出身です。

目標は、OLTPクエリに大きな影響を与えることなく、テーブルから古いデータをかじる、影響の少ないフォワードのみのジョブです。同じサーバー上にある必要のない別のテーブルにデータを挿入できます。LOADDATAINFILEに適した形式でファイルに書き込むこともできます。または、どちらも実行できません。その場合は、増分DELETEです。

不要な行を小さなバッチでアーカイブするためにすでに構築されており、ボーナスとして、削除する行を選択するクエリを台無しにした場合に備えて、削除された行をファイルに保存できます。

インストールは必要ありません。http://www.maatkit.org/get/mk-archiverを入手し、その上でperldocを実行して(またはWebサイトを読んで)ドキュメントを入手してください。

于 2009-08-26T00:11:05.773 に答える
1

一度に2000行としましょう。間にコミットします。テーブルに多くのインデックスがない限り、100万行はそれほど多くなく、これは高速です。

于 2009-08-23T16:42:21.420 に答える
0

複数のレコードをアーカイブ テーブルに移動した後、トランザクション テーブルから複数のレコードを削除しているときに、同様の問題に直面しました。

以前は一時テーブルを使用して、削除するレコードを識別していました。

「archive_temp」を使用して、インデックスなしでメモリに作成された ID を格納した一時テーブル。

したがって、元のトランザクション テーブルからレコードを削除している間、たとえば DELETE from tat where id in (select id from archive_temp); エラー「サーバーへの接続が失われました」を返すために使用されるクエリ

一時テーブルを作成した後、次のようにその一時テーブルにインデックスを作成しました: ALTER TABLE archive_tempADD INDEX( id);

この後、トランザクション テーブルから削除するレコードの数に関係なく、私の削除クエリは数秒以内に実行されていました。

したがって、インデックスを確認することをお勧めします。これが役立つことを願っています。

于 2020-11-18T09:28:49.113 に答える
-9

mysql のドキュメントによると、TRUNCATE TABLEは の高速な代替手段DELETE FROMです。これを試して:

TRUNCATE TABLE テーブル名

これを 50M 行で試したところ、2 分以内に完了しました。

注: 切り捨て操作はトランザクション セーフではありません。アクティブなトランザクションまたはアクティブなテーブル ロックの過程で試行するとエラーが発生する

于 2016-03-06T15:20:12.350 に答える