Обратите внимание, что указанный вами запрос удалит и дубликаты. Я бы предположил, что вы хотите сохранить то или другое.
Вот как я бы написать этот запрос:
DELETE t1 FROM table1 AS t1 JOIN table1 AS t2
ON t1.id > t2.id AND t1.field_name = t2.field_name;
Используя больше чем вместо не-равно-то, вы только удалить одну строку (позже один), вместо обоих.
Может помочь комплексный индекс (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
, пока вы случайно используете свою реальную базу данных в качестве базы данных по умолчанию!
Re ваших комментариев:
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)
Я собирался послать еще один пример запроса, но вы проверили это еще? Мне кажется, что обе записи будут удалены. – Fosco
Вы можете заменить «delete» на «select», чтобы проверить ваш запрос. –