NB Я понял, что ваш вопрос означает, что 2 строки считаются дубликатами, если два или более значений их столбцов равны.Если вы просто искали повторяющиеся значения в столбцах для той же строки, ответ @ GordonLinoff более уместен
В MySQL логические значения фактически представлены как 0 или 1
Для вашего примера из трех столбцов условие
(a.col1 = b.col1) + (a.col2 = b.col2) + (a.col3 = b.col3) >= 2
должно помочь
Например, если у вас есть уникальный столбец id
:
SELECT *
FROM your_table a
WHERE EXISTS (
SELECT 1
FROM your_table b
WHERE (a.col1 = b.col1) + (a.col2 = b.col2) + (a.col3 = b.col3) >= 2
AND a.id != b.id /** Don't consider the same row */
)
ОБНОВЛЕНИЕ
Я не удивлен, что вы получаете большую разницу во времени между 1К и 130К.Я предполагаю, что масштаб будет линейным, так что 15 с * 130/1 = 1950 с, что составляет около 30 минут для запроса полной таблицы.
Также не забывайте, что для каждой строки запрос проверяет вседругие строки для дубликатов.Вот почему просто получить всю таблицу быстрее.
Я надеюсь, что вам нужно использовать этот запрос как разовый, чтобы идентифицировать дубликаты.В противном случае это указало бы на некоторую неудачную структуру базы данных и, вероятно, таблицу можно было бы реорганизовать для лучшего соответствия ее назначению.Это проблема XY, на которую @apokryfos ссылается в своем комментарии на ваш вопрос.
Приведенный выше запрос не позволит использовать какие-либо индексы для столбцов из-за сложного условия.
Вы можете потенциально быстрее достичь результата, используя UNION ALL
, при условии, что у вас есть индивидуальный индекс для некоторых столбцов, а id
- это PK таблицы.
SELECT base.*
FROM your_table base
JOIN (
SELECT a.id, 1 col_match
FROM your_table a
WHERE EXISTS (
SELECT 1
FROM your_table b
WHERE b.col1 = a.col1
AND b.id != a.id
)
UNION ALL
SELECT a.id, 1 col_match
FROM your_table a
WHERE EXISTS (
SELECT 1
FROM your_table b
WHERE b.col2 = a.col2
AND b.id != a.id
)
UNION ALL
SELECT a.id, 1 col_match
FROM your_table a
WHERE EXISTS (
SELECT 1
FROM your_table b
WHERE b.col3 = a.col3
AND b.id != a.id
)
) raw
ON raw.id = base.id
GROUP BY base.id
HAVING SUM(raw.col_match) >= 2
Может показаться здоровенным, но его легко можно динамически построить на прикладном уровне для ваших десяти и более столбцов.
Имейте в виду, что если у вас больше дубликатов, чем уникальных, это можетимеет смысл инвертировать эту логику.