2010-08-02 2 views
2

У меня есть таблица mysql, в которой хранятся журналы обслуживания для датчиков. Я хотел бы спроектировать запрос, который находит случаи, когда данный датчик был отремонтирован/сохранен по той же причине. (. Периодическая задача искатель)Поиск дубликатов записей в mysql на основе битмаски

Моей таблица (упрощенная) выглядит следующим образом:

id name  mask 
== ====  ==== 
11 alpha 0011 
12 alpha 0010 
13 alpha 0100 
14 beta  0001 

поле маски битовый, где каждая позиция представляет собой особый вид ремонта. Мне удалось успешно выяснить, как сравнить битмаску (per this question), но попытка включить ее в запрос оказывается более сложной, чем я думал.

Учитывая приведенные выше примеры образцов, применяются только идентификаторы 11 и 12, так как они оба имеют 1 в третьем положении маски.

Вот что я пытался, и почему он не работает:


1. Никогда не заканчивается ...
Этот запрос кажется бежать навсегда, я не думаю, что он работает так, как Я хочу.

SELECT t1.id, t1.name 
FROM data t1 
LEFT OUTER JOIN data t2 
ON (CONV(t1.mask,2,10) & CONV(t2.mask,2,10) > 0) 
GROUP BY t1.name 
HAVING COUNT(*) >1; 

2. Неполное запрос ...
Я думал о создании вида, только разобрать датчики, которые на самом деле имеют более чем одну запись в таблице. Я не был уверен, куда идти отсюда.

SELECT COUNT(t1.name) AS times, t1.name, t1.id, t1.mask 
FROM data AS t1 
GROUP BY t1.name ASC 
HAVING times > 1; 

Любые предложения по этому поводу?

ответ

2

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

Джим прав, поскольку запрос приводит к декартовому продукту. Если этот запрос должен быть возвращен негрупповым и нефильтрованным, вы можете ожидать (SELECT POW(COUNT(*), 2) FROM data) результатов. Кроме того, любая форма внешнего соединения не нужна, поэтому стандартное внутреннее соединение - это то, что вы хотите здесь (не то, чтобы оно имело значение с точки зрения производительности, это более уместно).

Необходимо также другое условие соединения, t1.id != t2.id, чтобы каждая запись не соответствовала самой.

SELECT t1.id, t1.name 
FROM data t1 
JOIN data t2 
    ON t1.name = t2.name 
    AND t1.id != t2.id  // 
WHERE CONV(t1.mask, 2, 10) & CONV(t2.mask, 2, 10) > 0 
GROUP BY t1.name 
HAVING COUNT(*) > 1; 

Ваш запрос неполный:

SELECT t1.id, t1.name, t1.mask 
FROM data t1 
WHERE t1.name IN (SELECT t2.name FROM data t2 GROUP BY t2.name HAVING COUNT(*) > 1); 

SELECT t1.id, t1.name, t1.mask 
FROM data t1 
WHERE EXISTS (SELECT 1 FROM data t2 WHERE t2.name = t1.name GROUP BY t2.name HAVING COUNT(*) > 1); 

Off верхней части моей головы, я не могу вам сказать, какие из них будут работать лучше. Если индексируется data.name (и я надеюсь, что это так), стоимость для любого запроса должна быть довольно низкой.Первый будет кэшировать копию подзаголовка, тогда как последний будет выполнять несколько запросов против индекса.

Одной из основных задач оптимизации (оставив структуру таблицы в целом нетронутой) было бы преобразование поля маски в неподписанный целочисленный тип данных, тем самым сохраняя много вызовов до CONV().

WHERE CONV(t1.mask, 2, 10) & CONV(t2.mask, 2, 10) > 0 

становится

WHERE t1.mask & t2.mask > 0 

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

id name  mask 
== ====  ==== 
11 alpha 1101 

станет

id name value 
== ==== ===== 
11 alpha  1 
12 alpha  4 
13 alpha  8 

Теперь, стратегически расположенных указательный на name и value делает запрос, кусок торт

SELECT name, value 
FROM data 
GROUP BY name, value 
HAVING COUNT(*) > 1; 

Я надеюсь, что это поможет.

0

Разбить маску в реальных столбцах. RDMB не любят битовые поля.

+0

В идеале это будет отношение таблицы к таблице, но перестройка структуры БД на данном этапе невозможна. – JYelton

0

Ваше соединение приводит к декартовому продукту таблицы с самим собой. Добавьте `t1.name = t2.name 'к соединению, давая кучу (много) меньших декартовых продуктов, по одному на уникальное имя, что значительно ускорит процесс.

Смежные вопросы