Обратите внимание, что показанный вами запрос удалит оба дубликата. Я предполагаю, что вы хотите оставить один или другой.
Вот как бы я написал этот запрос:
DELETE t1 FROM table1 AS t1 JOIN table1 AS t2
ON t1.id > t2.id AND t1.field_name = t2.field_name;
Используя вместо "not-equals-to" больше-чем, вы удаляете только одну строку (более позднюю) вместо обеих.
Может помочь составной индекс над (id, field_name). Вы должны подтвердить это с помощью MySQL EXPLAIN
, чтобы получить отчет по оптимизации. Но EXPLAIN
поддерживает только SELECT
запросы, поэтому вы должны выполнить эквивалентный SELECT
для подтверждения оптимизации:
EXPLAIN SELECT * FROM table1 AS t1 JOIN table1 AS t2
ON t1.id > t2.id AND t1.field_name = t2.field_name;
Вы также спрашивали о тестировании. Я бы рекомендовал скопировать образец строк, содержащих дубликаты, в таблицу в вашей базе данных test
:
CREATE TABLE test.table1test SELECT * FROM realdb.table1 LIMIT 10000;
Теперь вы можете проводить эксперименты с данными вашего образца, пока не убедитесь, что решение DELETE
является правильным.
USE test;
SET autocommit = 0;
DELETE ...
ROLLBACK;
Я бы порекомендовал назвать вашу скретч-таблицу в базе данных test
чем-то отличным от вашей реальной таблицы в вашей реальной базе данных. На всякий случай, если вы запускаете экспериментальный DELETE
, в то время как вы все еще случайно используете вашу реальную базу данных в качестве базы данных по умолчанию!
Ваши комментарии:
USE test
- встроенная команда клиента mysql. Он устанавливает базу данных test
в качестве базы данных по умолчанию. Это будет база данных по умолчанию, когда вы называете таблицы в своих запросах, не квалифицируя их с именем базы данных. См http://dev.mysql.com/doc/refman/5.1/en/use.html
SET autocommit = 0
отключает поведение по умолчанию для фиксации транзакции для каждого запроса неявно. Таким образом, вы должны явно дать команду COMMIT
или ROLLBACK
, чтобы завершить транзакцию. См http://dev.mysql.com/doc/refman/5.1/en/commit.html
Стоит использовать ROLLBACK
, когда вы экспериментируете, потому что он отбрасывает изменения, сделанные в этой транзакции. Это быстрый способ вернуться к исходному состоянию ваших тестовых данных, чтобы вы могли попробовать другой эксперимент.
DELETE t1
это не опечатка. DELETE
удаляет строки, а не целые таблицы. t1
- это псевдоним каждой строки , которая удовлетворяет условиям оператора (хотя возможно, что условия включают каждую строку в таблице). См. Описание удаления нескольких таблиц на http://dev.mysql.com/doc/refman/5.1/en/delete.html
Вроде как, когда вы запускаете цикл в PHP и используете переменную для итерации по циклу: for ($i=0; $i<100; ++$i)
... Переменная $i
принимает ряд значений, и каждый раз, когда в цикле другое значение.
Вот демонстрация, показывающая, как мое решение удаляет несколько дубликатов. Я запустил это в своей базе данных test
и вставил результат прямо из моего командного окна:
mysql> create table table1 (id serial primary key, field_name varchar(10));
Query OK, 0 rows affected (0.45 sec)
mysql> insert into table1 (field_name)
values (42), (42), (42), (42), (42), (42);
Query OK, 6 rows affected (0.00 sec)
Records: 6 Duplicates: 0 Warnings: 0
mysql> select * from table1;
+----+------------+
| id | field_name |
+----+------------+
| 1 | 42 |
| 2 | 42 |
| 3 | 42 |
| 4 | 42 |
| 5 | 42 |
| 6 | 42 |
+----+------------+
6 rows in set (0.00 sec)
mysql> delete t1 from table1 t1 join table1 t2
on t1.id > t2.id and t1.field_name = t2.field_name;
Query OK, 5 rows affected (0.00 sec)
mysql> select * from table1;
+----+------------+
| id | field_name |
+----+------------+
| 1 | 42 |
+----+------------+
1 row in set (0.00 sec)