Linodeの1GB1CPUSSD仮想マシンのMySQL5.5で次のステートメントを実行しています。
DELETE table
FROM (
SELECT MAX(id) id, field
FROM table
GROUP BY field
) temp_table
INNER JOIN table
ON table.field = temp_table.field
WHERE table.id != temp_table.id
Sending data
状態で24時間以上スタックしているのですが、その理由がわかりました。実行プランがひどいです。
mysql> EXPLAIN SELECT 1 FROM (SELECT MAX(id) id, field FROM table GROUP BY field) temp_table INNER JOIN table ON table.field = temp_table.field WHERE table.id != temp_table.id
+----+-------------+------------+------+---------------+------+---------+------+--------+---------------------------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+------------+------+---------------+------+---------+------+--------+---------------------------------+
| 1 | PRIMARY | <derived2> | ALL | NULL | NULL | NULL | NULL | 381888 | |
| 1 | PRIMARY | users | ALL | NULL | NULL | NULL | NULL | 984873 | Using where; Using join buffer |
| 2 | DERIVED | users | ALL | NULL | NULL | NULL | NULL | 984873 | Using temporary; Using filesort |
+----+-------------+------------+------+---------------+------+---------+------+--------+---------------------------------+
3 rows in set (46.12 sec)
(MySQL5.5ではEXPLAIN DELETE
が許可されていないため、 this answerのようにEXPLAIN SELECT 1
で実行しています)
EXPLAIN
自体だけが完了するのに46秒かかることに注意してください。
この声明を止めて、より良いことをしようとすべきですか、それとも待つべきですか?
クエリが何をしているのかわかります。大量の行を削除し、すべてのフィールドに最後に挿入されたIDを保持しようとしています。
私にはもっと良い方法があります。
DROP TABLE IF EXISTS keys_to_keep;
CREATE TABLE keys_to_keep
(
id INT NOT NULL,
PRIMARY KEY (id)
);
INSERT INTO keys_to_keep SELECT MAX(id) FROM mytable GROUP BY field;
CREATE TABLE mytable_new LIKE mytable;
INSERT INTO mytable_new
SELECT B.* FROM keys_to_keep A INNER JOIN mytable B USING (id);
ALTER TABLE mytable RENAME mytable_old;
ALTER TABLE mytable_new RENAME mytable;
Mytableを確認してください。フィールドが最後に出現するだけの場合は、次のことができます。
DROP TABLE keys_to_keep;
DROP TABLE mytable_old;
私は以前にこのテクニックをお勧めしました
Oct 20, 2014
: レプリケーションを使用して大きなテーブルからデータを削除するDec 20, 2013
: CSVファイルからの大量のMySQL削除Jul 09, 2012
: TRUNCATE TABLEに非常に長い時間がかかる原因は何ですか?代わりにソフト削除を行うことについても説明しました(削除済みとマークされたIDの追加のマッピングテーブル、または削除された行にフラグを立てるための追加の列を維持する必要があります)。
Feb 15, 2012
: ソフト削除を実装する方法は?Mar 05, 2012
: データベースの同期およびソフト削除シナリオでのトゥームストーンテーブルと削除済みフラグNov 07, 2012
: 非常に長時間実行されるKILLコマンドについて何かできますか?Aug 07, 2013
: 重複レコードを削除する方法EXPLAIN
はサブクエリを評価したため、非常に時間がかかりました。おそらく、INDEX(field, id)
がないため、サブクエリに非常に時間がかかりました。
テーブルの大きなチャンクを削除する場合、保持したいものすべてを新しいテーブルにコピーしてから、RENAME
を使用してテーブルを交換する方が速いことがよくあります。
または、可能であれば、主キーをウォークスルーして、100〜1000のチャンクで削除を実行することもできます。詳細については 私のブログを削除 。