В очередной раз выручил Постгрес.

По работе я много занимаюсь отчетностью: генерю CSV и эксельки со всякими цифрами. Дело это не хитрое, но много нюансов: нужно собрать данные из десяти источников, очистить, переколбасить, построить прямые и обратные индексы. В идеале распараллелить. Потом пробежаться по коллекциям и записать итоговый документ.

Поскольку дело происходит в лямбде, я очень стеснен в ресурсах и времени. Процессор медленный, памяти и диска немного, а на выполнение дается не более 15 минут. Это только кажется много, а на самом деле первые 7 минут уходят только на то, чтобы скачать архивы.

Из последнего: в папке S3 лежит огромный CSV на 10 миллионов записей. Нужно выбрать из него одно подмножество, затем второе, а потом склеить их по id = parent_id.

Написал на Кложе черновик — работает, занимает 11 минут. Можно плюнуть и оставить, но 11 минут — это уже близко к 15 минутам, а значит, можно получить таймаут. Переписал с параллельной обработкой — стало 5 минут, волноваться не о чем.

А потом смотрю и думаю: ты же, дурачок, написал ровно то, что делает база данных. Только раз в десять медленней и костыльней. Убери быдлокод, загони CSV в базу и выполни запрос — получишь то же самое.

Так и сделал: получаю из Амазона стрим с CSV-содержимым. Не скачивая его на диск, направляю прямиком в Постгрес во временную таблицу (апишка COPY FROM STDIN). Тот загружает 10 миллионов записей за 40 секунд. Потом посылаю SQL с двумя подзапросами и джоином — результат готов за 15 секунд. Его даже не нужно писать в CSV самому. Вызываешь COPY TO STDOUT — и Постгрес сам записывает CSV на диск. Точнее, в стрим, который я направляю в файл.

Минус два экрана быдлокода, быстрее почти на порядок — все довольны, все смеются. Сразу после этой доработки мне написал один человек — мол, репорт хороший, только надо еще одну табличку заджойнить. Да не вопрос.

Отсюда мораль — если что-то можно поручить базе, поручайте базе. Постгрес уже 20 лет делает джоины и проекции таблиц. Вероятность того, что вы сделаете быстрее, стремится к нулю.

Ради интереса глянул на SQLite — зачем брать серверный Постгрес, если можно локально справиться? Оказалось, SQLite не умеет импортировать CSV. Такая команда есть в интерактивном шелле, а в протоколе обмена — нет. А в Постгресе есть потоковый COPY, поэтому выбора не остается.

Есть у нас сервис, который пилят другие люди. Там логика крутится вокруг CSV и пакетного импорта в другие сервисы. Посмотрел и ужаснулся: километры кложурного быдлокода можно заменить импортом в базу и парой-тройкой запросов. Дай бог доберусь, переделаю.