Поиск ближайших значений в MySQL
Иногда возникает необходимость поиска значений по базе данных находящихся в непосредственной близости от определенного значения. Это могут быть даты или числовые значения.
Я сейчас участвую в стартапе и возникла задача поиска заведений предоставляющих скидку близкой к той что у просматриваемого пользователем заведения.
Предположим что есть 5 заведений:
Заведение 1 | 10 |
Заведение 2 | 13 |
Заведение 3 | 15 |
Заведение 4 | 16 |
Заведение 5 | 16 |
И нужно их отсортировать по близости значения скидки. Простой ORDER BY не подойдет т.к. он ищет ближайшие значения только в одну сторону, либо в большую, либо в меньшую.
Предположим что мы открыли заведение 3, и нужно получить список ближайших по скидке заведений, запрос можно сделать так:
SELECT *, ABS( discount - 15 ) AS discountDistance FROM companys ORDER BY discountDistance
Я тут намеренно не исключал Заведение 3 из списка результатов чтоб не усложнять пример, результатом вывода будет следующее:
Заведение 3 | 15 |
Заведение 4 | 16 |
Заведение 5 | 16 |
Заведение 2 | 13 |
Заведение 1 | 10 |
Такой запрос без проблем работает с небольшим кол-вом данных, но на больших таблицах его выполнение может оказаться неприемлемо долгим, и зачастую нам не нужно выбирать все записи из таблицы, а достаточно например трех.
Т.к. мы точно знаем что нам нужно мы можем помочь MySql c выполнением задачи ограничив набор данных которые базе данных придется обрабатывать. Мы точно знаем что интересующие нас значения находятся в пределах трех ближайших нижних или трех ближайших верхних значений.
Для этого мы объединим результаты работы двух SELECT команд и получим список состоящий максимум из 7 полей, из которых уже сможем быстро отобрать 3 ближайших.
SELECT *, ABS( discount - 15 ) AS discountDistance FROM ( ( SELECT * FROM companys WHERE discount >=15 ORDER BY discount LIMIT 3 ) UNION ALL ( SELECT * FROM companys WHERE discount < 15 ORDER BY discount DESC LIMIT 3 ) ) AS n ORDER BY discountDistance LIMIT 3
Второй вариант еще не тестировал на больших объема данных, но должно быть в разы быстрее.
1 комментарий
Вы можете оставить комментарий