ОписаниеЭффективный способ для вычисления количества паросочетаний между двумя столбцами в MySQL
У меня есть таблица MySQL, как следующему:
CREATE TABLE `ticket` (
`ticket_id` int(11) NOT NULL AUTO_INCREMENT,
`ticket_number` varchar(30) DEFAULT NULL,
`pick1` varchar(2) DEFAULT NULL,
`pick2` varchar(2) DEFAULT NULL,
`pick3` varchar(2) DEFAULT NULL,
`pick4` varchar(2) DEFAULT NULL,
`pick5` varchar(2) DEFAULT NULL,
`pick6` varchar(2) DEFAULT NULL,
PRIMARY KEY (`ticket_id`)
) ENGINE=InnoDB AUTO_INCREMENT=19675 DEFAULT CHARSET=latin1;
Давайте также предполагаю, мы имеем следующие значения уже сохранены в DB:
+-----------+-------------------+-------+-------+-------+-------+-------+-------+
| ticket_id | ticket_number | pick1 | pick2 | pick3 | pick4 | pick5 | pick6 |
+-----------+-------------------+-------+-------+-------+-------+-------+-------+
| 655 | 08-09-21-24-46-52 | 8 | 9 | 21 | 24 | 46 | 52 |
| 658 | 08-23-24-40-42-45 | 8 | 23 | 24 | 40 | 42 | 45 |
| 660 | 07-18-19-20-22-31 | 7 | 18 | 19 | 20 | 22 | 45 |
| ... | ... | ... | ... | ... | ... | ... | ... |
| 19674 | 06-18-33-43-49-50 | 6 | 18 | 33 | 43 | 49 | 50 |
+-----------+-------------------+-------+-------+-------+-------+-------+-------+
Теперь моя цель состоит в том, чтобы сравнить каждый билет с каждой другой в таблице (кроме себя), с точки зрения thei r соответствующие значения в поле ticket_number
(6 элементов в наборе, разделены на -
). Иными словами, предположим, что я сравниваю ticket_id = 655
с ticket_id = 658
, с точки зрения элементов в их уважаемых полях ticket_number
, то обнаружим, что в обоих наборах появляются элементы 08
и 24
. Если сравнить ticket_id = 660
с ticket_id = 19674
, то у нас есть только одно совпадение: 18
.
То, что я на самом деле, используя для проведения этих сравнений является следующий запрос:
select A.ticket_id, A.ticket_number, P.ticket_id, P.ticket_number, count(P.ticket_number) as cnt from ticket A inner join ticket P on A.ticket_id != P.ticket_id
where
((A.ticket_number like concat("%", lpad(P.pick1,2,0), "%"))
+ (A.ticket_number like concat("%", lpad(P.pick2,2,0), "%"))
+ (A.ticket_number like concat("%", lpad(P.pick3,2,0), "%"))
+ (A.ticket_number like concat("%", lpad(P.pick4,2,0), "%"))
+ (A.ticket_number like concat("%", lpad(P.pick5,2,0), "%"))
+ (A.ticket_number like concat("%", lpad(P.pick6,2,0), "%")) > 3) group by A.ticket_id
having cnt > 5;
То есть, первый я создаю INNER JOIN
конкатенации всех строк с различными ticket_id
, а затем я сравниваю каждый P.pickX
(X=[1..6]
) с A.ticket_number
итоговой операции INNER JOIN
, и я подсчитываю количество совпадений между обоими наборами.
Наконец, после выполнения, я получаю что-то вроде этого:
+-------------+-------------------+-------------+-------------------+-----+
| A.ticket_id | A.ticket_number | P.ticket_id | P.ticket_number | cnt |
+-------------+-------------------+-------------+-------------------+-----+
| 8489 | 14-21-28-32-48-49 | 2528 | 14-21-33-45-48-49 | 6 |
| 8553 | 02-14-17-38-47-53 | 2364 | 02-30-38-44-47-53 | 6 |
| 8615 | 05-12-29-33-36-43 | 4654 | 12-21-29-33-36-37 | 6 |
| 8686 | 09-13-29-34-44-48 | 6038 | 09-13-17-29-33-44 | 6 |
| 8693 | 01-10-14-17-42-50 | 5330 | 01-10-37-42-48-50 | 6 |
| ... | ... | ... | ... | ... |
| 19195 | 05-13-29-41-46-51 | 5106 | 07-13-14-29-41-51 | 6 |
+-------------+-------------------+-------------+-------------------+-----+
Проблема
Проблема заключается в том, что я выполняю это для таблицы 10476 rows
, что приводит к более загар 100 миллионов ticket_number
против pickX
, чтобы сравнить, продолжая около 172 секунд, чтобы завершить. Это слишком медленно.
ЗАДАЧА
Моя цель состоит в том, чтобы сделать это исполнение настолько быстро, насколько это возможно, с тем, чтобы завершить менее чем за второй, так как это должно работать в режиме реального времени.
Возможно ли это?
Имея имена столбцов с номерами в нем почти всегда являются признаком плохого дизайна таблицы. –
Итак, любые предложения? – juanba1984
Да, измените дизайн стола. Вам нужен другой стол для ваших «выборов», что бы это ни было. –