Поиск ближайших значений в MySQL

8 227 просмотров 1 комментарий 20 января 2016

Иногда возникает необходимость поиска значений по базе данных находящихся в непосредственной близости от определенного значения. Это могут быть даты или числовые значения.

Я сейчас участвую в стартапе и возникла задача поиска заведений предоставляющих скидку близкой к той что у просматриваемого пользователем заведения.

Предположим что есть 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 комментарий

Возьму на заметку. Спасибо за статью

Вы можете оставить комментарий