Равномерная выборка в MySql

Встала интересная задача — за произвольный срок показать динамику процесса.
Произвольный срок может быть и годом и тремя годами — показатели собираются каждый день, пока процесс установлен на мониторинг показателей. То есть даты могут идти не по-порядку, процесс может быть снят с мониторинга несколько месяцев, потом снова возвращен. Загружать на график все значения за период не просто бессмысленно, но и вредно, и загрузку страницы это замедлит и браузер сделает менее отзывчивым.
Поэтому надо выбрать порядка, скажем, 30 значений: этого будет достаточно, чтобы судить об общей динамике за выбранный период и выглядеть на графике будет это замечательно и нагрузка на браузер нулевая.
Самая главная сложность — это сделать равномерную выборку среди значений которые идут не по-порядку по дате, по ИД и подавно не по-порядку.
Для начала: как понять, что среди значений отсортированных предварительно по возрастанию даты понять, что это именно каждое N/30 значение?
Первое, что приходит в голову — это остаток от деления порядкового номера на N/30. Допустим, значений у нас 100.
Если отбирать записи, у которых порядковый номер делится на 3, получится набор из 33 записей, это как-бы нормально.
Хуже если записей 45, тогда, если округлить делитель до 2 получим 22 результата в наборе, если в меньшую сторону — до одного — то аж 45. Нехилый такой разброс.
Значит, чтобы всегда получать 30 записей в результирующем наборе, надо учитывать значение N/30 хотя бы до одного знака после запятой.
Берем, умножаем на 10 результат деления N/30, умножаем на 10 порядковый номер и остаток от целочисленного деления номера на коэффициент должен быть не точно нулем, а меньше 10.
Пример получившегося кода для MySql:

# Получаем количество записей 
SELECT COUNT(*) AS `N` 
FROM `table` 
WHERE `date` BETWEEN :dateFrom AND :dateTo ;
# koef = N / 30 * 10
# Задаем начальное значение счетчика записей
SET @numRow = 0;
# Делаем выборку
SELECT *, (@numRow := @numRow + 10) as `numRow`
FROM `table`
WHERE @numRow % :koef < 10 
    AND `date` BETWEEN :dateFrom AND :dateTo
ORDER BY `date`

Добавить комментарий