Неэффективная оптимизация
May. 23rd, 2017 08:27 am С оптимизацией получился облом.
Напомню, что была попытка соптимизировать запрос с select ... where date(field) in (...) group by ...
. Я в курсе, что конструкция field in (...)
сама по себе дорогая, но вполне приемлема, если потеря скорости незначительна, а альтернатива может оказаться ещё дороже.
В моей ситуации потеря скорости оказалась слишком велика, чтобы её игнорировать.
Попробовал другое "дешёвое" решение — внедрить ограничение диапазона, где код where date(field)≥{min_time} and date(field)<{max_time}
призван был сократить первоначальную выборку, и уже после этого работал бы var in (...)
. Нужно было планчик составить, но лениво. А потом оказалось что и var in
лишний. С выборкой нужных дат в самом скрипте всё оказалась гораздо быстрее. И поначалу всё заработало как надо. И дело даже не в кешировании. Потому как регулярно, раз в час поступают новые данные.
Эффект был кажущимся из-за того, что на момент тестирования дат было не так много и group by
на все эти даты не сильно тормозил. Но наступление события "С", ради которого весь этот сыр-бор, задержалось. И получилось что между первой и последней датой времени прошло настолько много, что быстродействие от экономии на отказе от var in
полностью пожралось group by
. Долгим и бессмысленным.
Ещё бы:
- 4 таблицы: 1.2млн, 1.3млн, 26млн и 27млн записей.
- интересующие данные (без уточнения по дате) составляют 64К, 10К, 130К и 20К записей.
- в таблицах сидит timestamp, а выборку и результат нужно делать от функции по нему. Хоть через substr, хоть по date.
Можно было плюнуть и вернуться к старой схеме, но "мы не привыкли отступать"© и это оскорбляет эстетическое чувство.
Поэтому пришлось делать красиво и по-полной схеме. При обращении к странице, скрипт запрашивает данные, уже сгруппированные по дате и лежащие в специальной дочерней таблице. Если на определённую дату данных нет, то запрашиваются данные в родительской таблице. Если они оказываются полными за указанную дату (24 часа, 1440 минут или 86400 минут), то они вставляются в дочернюю таблицу и в следующий раз будут извлекаться оттуда. Считать их заново будет не нужно. Операция сия была необходима для одного определённого объекта, так что пухнуть дочерние таблицы не будут. При периодическом опросе данные за прошедшие дни обстчитываются постепенно, и только за текущий - постойнно. В результате подтормаживание составляет при пересчёте прошедших суток считанные доли секунды, а за текущую дату - даже не заметно. Всё-таки выборка по timestamp ≥ {time} and (timestamp < {time} + INTERVAL 1 DAY)
гораздо быстрее, чем упоминавшиеся ранее конструкции. Да и group by
нужно будет убрать, т.к. алгоритм и ткак каждый раз выдёргивает по одной строке.
Зато теперь всё классно. :)