LINUX.ORG.RU

MYSQL выбрать строки с дублями полей

 ,


0

1

Добрый день! Помогите накидать запрос для отбора полей с дублями. SQL последний раз юзал лет 5 назад, ничего не помню. Есть таблица, `files` в ней есть строки с полем `filepath`, нужно отобрать строки с одинаковыми значениями. Пробую такой запрос

SELECT * FROM `files` 
GROUP BY `filepath` 
HAVING COUNT(*) > 1

Получаю строки, но они группируются типа так

1 /etc/1

2 /etc/2

А мне надо

1 /etc/1

2 /etc/1

3 /etc/1

4 /etc/2

5 /etc/2

★★

уберёшь group by - не будет работать having.
либо добавь order by filepath, либо используй where и sort by.

anonymous
()

не слушай анонимусов


SELECT * FROM `files` 
WHERE `filepath` IN (
SELECT `filepath` FROM `files` 
GROUP BY `filepath` 
HAVING COUNT(`filepath`) > 1
)

надеюсь, с синтаксисом не напутал

bvn13 ★★★★★
()
Последнее исправление: bvn13 (всего исправлений: 1)
Ответ на: комментарий от Sora

Вместо него WHERE, как анонимус выше посоветовал.

CYB3R ★★★★★
()
Ответ на: комментарий от bvn13

В старых мускулях вложенные запросы могут работать довольно медленно (не использовать индекс). Если запрос не одноразовый то перед тем как его использовать стоит посмотреть план исполнения (explain select ...)

MrClon ★★★★★
()
Ответ на: комментарий от Sora

А база сильно большая? Если там не миллионымиллиарды строк то при фулскане должен просто хрустеть хардом несколько секунд/минут.
Версия мускуля какая?

Зачастую можно переписать вложенный селект на джойн таблицы на саму себя, попробуй.

MrClon ★★★★★
()
Ответ на: комментарий от Sora

И запрос намертво виснет? А есди подождать минуту другую? Покажи план выполнения запроса (допиши перед запросом explain).

MrClon ★★★★★
()

Можно сперва встречный вопрос, а зачем их надо найти? Если просто надо дропнуть все дубликаты для данной записи, то находить их для этого не надо.

Еще можно пометить все дубликаты с использованием дополнительной колонки и джойна (http://www.mysqltutorial.org/mysql-update-join/). Задно сразу отличить дубликат от оригинала.

Jaberwock ★★★
()
Ответ на: комментарий от Jaberwock

Надо дропнуть. Спасибо, дома почитаю!

Sora ★★
() автор топика
Ответ на: комментарий от MrClon

mysql> EXPLAIN SELECT * FROM `files` WHERE `filepath` IN ( SELECT `filepath` FRO M `files` GROUP BY `filepath` HAVING COUNT(`filepath`) > 1 ) -> ;

+----+--------------------+-------+------+---------------+------+---------+------+-------+---------------------------------+

| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |

+----+--------------------+-------+------+---------------+------+---------+------+-------+---------------------------------+

| 1 | PRIMARY | files | ALL | NULL | NULL | NULL | NULL | 28276 | Using where |

| 2 | DEPENDENT SUBQUERY | files | ALL | NULL | NULL | NULL | NULL | 28276 | Using temporary; Using filesort |

+----+--------------------+-------+------+---------------+------+---------+------+-------+---------------------------------+

2 rows in set (0.00 sec)

Sora ★★
() автор топика
Ответ на: комментарий от MrClon

mysql> SHOW INDEX FROM files;

+-------+------------+-----------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+

| Table | Non_unique | Key_name | Seq_in_index | Column_name | Collation | Cardinality | Sub_part | Packed | Null | Index_type | Comment | Index_comment |

+-------+------------+-----------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+

| files | 0 | PRIMARY | 1 | fid | A | 28276 | NULL | NULL | | BTREE | | |

| files | 1 | uid | 1 | uid | A | 271 | NULL | NULL | | BTREE | | |

| files | 1 | status | 1 | status | A | 54 | NULL | NULL | | BTREE | | |

| files | 1 | timestamp | 1 | timestamp | A | 28276 | NULL | NULL | | BTREE | | |

+-------+------------+-----------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+ 4 rows in set (0.01 sec)

Места полно. 600Гб.

Sora ★★
() автор топика
Ответ на: комментарий от MrClon

В старых мускулях вложенные запросы могут работать довольно медленно

И в новых тоже. Иной раз на совсем простой таблице SELECT .. WHERE ... IN (SELECT ..) зависает на десятки секунд. В то время, как JOIN отрабатывает за тысячные доли секунды. И даже если JOIN неприменим, то создание временной таблицы и выборка через JOIN уже с ней срабатывает за десятые-сотые доли секунды. Просто воспринимаю это как данность :D

KRoN73 ★★★★★
()
Ответ на: комментарий от Wolfram

mysql> EXPLAIN SELECT t1.fid, t1.filepath FROM files t1, (SELECT filepath FROM f iles GROUP BY filepath HAVING COUNT(filepath) > 1 ) t2 WHERE t1.filepath = t2.fi lepath;

+----+-------------+------------+------+---------------+------+---------+------+-------+---------------------------------+

| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |

+----+-------------+------------+------+---------------+------+---------+------+-------+---------------------------------+

| 1 | PRIMARY | <derived2> | ALL | NULL | NULL | NULL | NULL | 1315 | |

| 1 | PRIMARY | t1 | ALL | NULL | NULL | NULL | NULL | 28276 | Using where; Using join buffer |

| 2 | DERIVED | files | ALL | NULL | NULL | NULL | NULL | 28276 | Using temporary; Using filesort |

+----+-------------+------------+------+---------------+------+---------+------+-------+---------------------------------+

3 rows in set (0.61 sec)

Sora ★★
() автор топика
Ответ на: комментарий от KRoN73

В последних версиях (то-ли с 5.5 то-ли с 5.6) что-то в оптимизаторе подкрутили на этот счёт, в каких-то случаях подапросы стали работать так-же быстро как джоины, а в некоторых случаях быстрее. На хабре был пост, искать лень.
Но в целом да, с подзапросами есть какая-то попа.

А в данном случае попа усиливается тем что по столбцу filepath нет индекса.

Короче для начала нужно добавить индекс (если запрос не одноразовый), потому-что без индексов жить в принципе грустно. А потом ещё и переписать запрос на join, если всё-равно дико тормозить будет.

MrClon ★★★★★
()
Ответ на: комментарий от Wolfram

Без индекса — всё тлен.
Мускуль пытается сортировать по filepath, а поскольку индекса там нет, а данных там много то сортировать он пытается в файле, и почему-то от этого запрос виснет намертво.

MrClon ★★★★★
()
Ответ на: комментарий от MrClon

В последних версиях (то-ли с 5.5 то-ли с 5.6) что-то в оптимизаторе подкрутили на этот счёт

5.6 не видел, в 5.5 и MariaDB 10.0 (я м MySQL 5.5 сразу на неё перелез) проблема актуальна.

А в данном случае попа усиливается тем что по столбцу filepath нет индекса.

Ну, это совсем грустно :)

Короче для начала нужно добавить индекс (если запрос не одноразовый)

Самое смешное, что в случае подзапросов часто выгодно создать временную таблицу, добавить там индекс и уже по ней делать JOIN. Нередко получается не сопоставимая разница, вместо десятков секунд или минут — десятые доли секунды на всё, включая создание временной таблицы и индексов.

KRoN73 ★★★★★
()
Ответ на: комментарий от MrClon

Нет, мне один раз решить проблему, обновляю CMS Drupal с 6 до 7, начались проблемы при переносе полей нод, не переносятся пути изображений, накопал что проблема с этой таблицей.

Проблема застарела, видно еще в 2010 году был некий косяк с базой. Надо ее один раз почистить и все.

Sora ★★
() автор топика
Ответ на: комментарий от MrClon

WAMP, место есть, это копия сайта у меня на нойте.

Sora ★★
() автор топика
Ответ на: комментарий от Sora

Тогда делай временную таблицу, или гугли как переписать подапрос на join, про это написано много

MrClon ★★★★★
()
Ответ на: комментарий от MrClon

Мускуль пытается сортировать

Там нет сортировки.

а данных там много

28276 строк, не много.

индекса там нет

Согласен, что индекс может помочь, но не факт.

Wolfram
()
Ответ на: комментарий от MrClon

Ты её не видишь, и я её не вижу, а она есть:

Using temporary; Using filesort

Я не об этой сортировке. Если добавить order by будет еще медленнее.

Wolfram
()
Ответ на: комментарий от Wolfram

Вот, ты её даже в виду не имеешь, а она всё-равно есть и всё-равно тормозит выполнение запроса вплоть до полного его зависания.

MrClon ★★★★★
()
Ответ на: комментарий от Wolfram

Запрос отработал как надо, спасибо огромное!

Sora ★★
() автор топика
Ответ на: комментарий от MrClon

Спасибо большое за помощь!

Sora ★★
() автор топика
Ответ на: комментарий от Jaberwock

Согласен. В данном случае UNIQUE будет актуальнее (только имя таблицы забыл). Но запись в таблицу через INSERT IGNORE придется делать.

Wolfram
()
Ответ на: комментарий от Wolfram

Читай выше, задача была дропнуть дубликаты. После удаления дубликатов можно или оставить юник и забыть про дубликаты навсегда или дропнуть юник и вернуться к прежнему ссостоянию но без дубликатов

INSERT IGNORE не нужен в любом случае.

Jaberwock ★★★
()
10 июля 2016 г.
Ответ на: комментарий от Jaberwock

SELECT * FROM (

SELECT * , COUNT( vId ) AS count FROM t_sklad_update u GROUP BY u.vId )u2 WHERE u2.count >1

anonymous
()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.