SQLinfo.ru - Все о MySQL

Форум пользователей MySQL

Задавайте вопросы, мы ответим

Вы не зашли.

#1 24.07.2013 04:00:14

dark_drakon
Участник
Зарегистрирован: 24.07.2013
Сообщений: 4

сосавление производительного запроса для выборки пересекающихся данных

Всем доброго времени суток.

Имеется таблица вида:
ID|k1|k2
*|1|554
*|1|34
*|1|354
*|1|353
*|1|654
...
*|2|4
*|2|34
*|2|34
*|2|124
*|2|6424
...

Поле ID интереса не представляет. Каждый элемент из поля k1 всегда имеет 15 значений в поле k2. Таблица может иметь больше миллиарда строк. У некоторых элементов k1 есть несколько одинаковых параметров k2.

На основании этой таблицы, нужно составить таблицу вида |ID|grp|k1|, где id не важен, k1 - это ключ из первой таблицы, grp - это номер группы ключей. Ключи k1 нужно сгруппировать по следующей логике: Если ключи из k1 имеют больше 5 совпадающих значений в столбце k2, то они принадлежат одной группе. Если ключ из k1 не имеет достаточного количества совпадающих значений - то он просто единственный член своей группы. Т.е. стоит задача группировки ключей имеющих пересечения параметров.

Скрипт группировки будет выполняться редко, но учитывая большой объем данных, нужно подумать над производительностью.
Можно задействовать вспомогательные таблицы. Т.к. количество параметров k2 у ключа k1 всегда одинаковое и равно 15 - то можно начальную таблицу сделать вида |id|k1|par1|par2|...|par15|, если это как-то повысит скорость выборки.

Если какому-либо гуру будет лень расписывать алгоритм решения в коде, то я буду рад прочитать любые идеи просто на уровне алгоритмов. Уже голову сломал над оптимальным алгоритмом. Тупым перебором решить можно, но учитывая то, что строк может быть больше миллиарда - то хочется иметь наиболее оптимальное решение.

Заранее благодарю всех высказавшихся по существу.

Неактивен

 

#2 24.07.2013 10:43:57

vasya
Архат
MySQL Authorized Developer
Откуда: Орел
Зарегистрирован: 07.03.2007
Сообщений: 5842

Re: сосавление производительного запроса для выборки пересекающихся данных

Можно одним запросом, который будет последовательно сравнивать значение с предыдущим и считать кол-во совпадений.
При наличии индекса на (k1,k2) будет выполняться без обращения к самой таблице (только по индексу).
Идею реализации см http://sqlinfo.ru/forum/viewtopic.php?id=1742

Если одинаковые параметры явление редкое, то сначала с помощью запроса

SELECT k1 from `таблица` GROUP BY k1 HAVING count(DISTINCT k2) < 11; -- выбираем только те k1, у которых кол-во уникальных значений k2 меньше 11

можно отсечь часть данных, где заведомо не будет нужного кол-ва совпадений. А для оставшихся k1 перебор.

Неактивен

 

#3 24.07.2013 10:52:42

vasya
Архат
MySQL Authorized Developer
Откуда: Орел
Зарегистрирован: 07.03.2007
Сообщений: 5842

Re: сосавление производительного запроса для выборки пересекающихся данных

Да, блин, легких путей мы не ищем. Не проснулся видимо ещё smile

SELECT k1, if(max(cc)>4,X,Y) grp FROM (SELECT k1, k2, count(DISTINCT k2) cc from `таблица` GROUP BY k1, k2) t GROUP BY k1;

где
X - номер группы, если есть больше 5 совпадающих значений в столбце k2
Y - номер группы, если меньше 5 совпадающих значений в столбце k2

Неактивен

 

#4 25.07.2013 01:15:02

dark_drakon
Участник
Зарегистрирован: 24.07.2013
Сообщений: 4

Re: сосавление производительного запроса для выборки пересекающихся данных

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

Постараюсь описать задачу поподробней.
Пусть это будет пример таблицы исходных данных: (Разнесу данные по столбцам для удобства визуального восприятия, но это все одна таблица из 3-х колонок)


|id|k1 |k2 |      |id|k1 |k2 |      |id|k1 |k2 |      |id|k1 |k2 |      |id|k1 |k2 |      |id|k1 |k2 |     
......................................................................................................
| *|1  |12 |      | *|2  |27 |      | *|3  |13 |      | *|4  |57 |      | *|5  |72 |      | *|6  |11 |
| *|1  |13 |      | *|2  |28 |      | *|3  |19 |      | *|4  |58 |      | *|5  |73 |      | *|6  |16 |
| *|1  |14 |      | *|2  |29 |      | *|3  |44 |      | *|4  |59 |      | *|5  |74 |      | *|6  |13 |
| *|1  |15 |      | *|2  |18 |      | *|3  |45 |      | *|4  |60 |      | *|5  |75 |      | *|6  |90 |
| *|1  |16 |      | *|2  |19 |      | *|3  |46 |      | *|4  |61 |      | *|5  |76 |      | *|6  |91 |
| *|1  |17 |      | *|2  |32 |      | *|3  |47 |      | *|4  |62 |      | *|5  |77 |      | *|6  |92 |
| *|1  |18 |      | *|2  |13 |      | *|3  |18 |      | *|4  |63 |      | *|5  |78 |      | *|6  |77 |
| *|1  |19 |      | *|2  |34 |      | *|3  |49 |      | *|4  |16 |      | *|5  |79 |      | *|6  |78 |
| *|1  |20 |      | *|2  |12 |      | *|3  |50 |      | *|4  |65 |      | *|5  |80 |      | *|6  |95 |
| *|1  |21 |      | *|2  |15 |      | *|3  |51 |      | *|4  |13 |      | *|5  |81 |      | *|6  |96 |
| *|1  |22 |      | *|2  |37 |      | *|3  |52 |      | *|4  |67 |      | *|5  |82 |      | *|6  |97 |
| *|1  |23 |      | *|2  |38 |      | *|3  |15 |      | *|4  |68 |      | *|5  |83 |      | *|6  |86 |
| *|1  |24 |      | *|2  |16 |      | *|3  |15 |      | *|4  |69 |      | *|5  |84 |      | *|6  |85 |
| *|1  |25 |      | *|2  |40 |      | *|3  |12 |      | *|4  |70 |      | *|5  |85 |      | *|6  |72 |
| *|1  |26 |      | *|2  |41 |      | *|3  |16 |      | *|4  |12 |      | *|5  |86 |      | *|6  |73 |


Все значения параметров k2 для каждого ключа k1 всегда разные между собой.

Результат обработки вышеуказанной таблицы имеет вид


id|grp|k1
* |1  |1
* |1  |2
* |1  |3
* |2  |5
* |2  |6
* |3  |4


Ключи 1,2,3 принадлежат 1 группе, т.к. имеют больше 5 общих параметров. (помечены красным) Ключ 4 не входит ни в одну группу, т.к. не имеет ни с кем больше 5 совпадений. Ключи 5 и 6 принадлежат одной группе, т.к. имеют больше 5 пересечений данных. (помечены зеленым)


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

Неактивен

 

#5 25.07.2013 12:19:27

vasya
Архат
MySQL Authorized Developer
Откуда: Орел
Зарегистрирован: 07.03.2007
Сообщений: 5842

Re: сосавление производительного запроса для выборки пересекающихся данных

SELECT t1.k1, t2.k1 FROM `таблица` t1 JOIN `таблица` t2 ON t1.k2=t2.k2 AND t1.k1<>t2.k1 GROUP BY 1,2 HAVING count(t2.k1)>4  AND t1.k1<t2.k1;


|1  |2 |   
|1  |3 |   
|2  |3 |     
|5  |6 |

Единственно, что приходит на ум, это получить табличку с парами ключей, имеющих 5 и более совпадений. И уже по этой табличке строить нужную вам выборку с группами. Берете последовательно каждый ключ. Если его в табличке нет, то это уникальная группа. Если есть, то ключи 1 и 2 входят одну группу. Если есть ещё записи с ключом №1, то проверяем относятся они к предыдущей группе(ам) или образуют новую.
В общем, насчет производительности очень серьезные сомнения.

Неактивен

 

#6 25.07.2013 13:07:04

dark_drakon
Участник
Зарегистрирован: 24.07.2013
Сообщений: 4

Re: сосавление производительного запроса для выборки пересекающихся данных

Спасибо за советы, буду думать дальше.

Неактивен

 

#7 25.07.2013 13:10:38

vasya
Архат
MySQL Authorized Developer
Откуда: Орел
Зарегистрирован: 07.03.2007
Сообщений: 5842

Re: сосавление производительного запроса для выборки пересекающихся данных

Поделитесь потом итогом размышлений. Тоже любопытно.

Неактивен

 

Board footer

Работает на PunBB
© Copyright 2002–2008 Rickard Andersson