Поскольку на вопрос никто не писал ответа - я напишу вариант.
Это не совсем ответ. Это скорее список сомнений.
Дело в том что
BigData в принципе не работает онлайн. Тоесть нельзя запускать анализ в ответ на мышко-клик пользователя и ожидать что это будет меньше 2.5 секунд. Таких задач никто не ставит. Если хотят чтоб пользователь что-то быстро получал - то готовят DataMart, OLAP-cube, или некий Gold (золотой) уровень материализовнных таблиц в парадигме lakehouse. Тоесть грубо говоря готовят данные к выдаче. Что только взять по ключу и показать. И на этом уровне обычно не ставят parquet а берут CosmosDb+Redis (key-value) чтоб браузер не ждал долго. Никаких агрегаций здесь быть не должно.
Как подготавливать эти уровни серебрянного или золотого представления данных - это отдельная задача. Есть микро-батчи или стриминг но в общем и целом нельзя делать в ответ на действие пользователя. Это делает pipeliene.
Второе. Как уже верно было подмечено "Сервер 4 ядра, 16 гб оперативки" -
это не конфигурация для Spark. Это просто какой-то сервак. Spark - это кластерная система и он имеет преимущества при работе в "импульсном
режиме в кластере" но ей нужен пул рабочих машин (хотя-бы штук 4-8) и файловая система наподобие hdfs или ее более современные вариации (s3/msBlobStorage). Это очень важно. Иначе не будет скейлится I/O.
Третье. Паркет (parquet) вообще
имеет сильные преимущества когда вы выбираете 45 столбцов из 4500. В этом случае дисковая оптимизация сработает лучше чем у реляционных систем и выберет ровно столько IOPS сколько надо для публикации именно 45 столбцов. В остальных случаях паркет только фейлит и лучше вам брать AVRO например или реляционные БД.
Четвертое.
Партишенинг. Очень часто бизнес запрашивает данные которые физически можно консолидировать по партишенам. Тоесть если ваш parquet-файл разрезать на периоды и допустим продукты то мы получим следующую физическую структуру файлов:
sales/year=2022/product=001/part-00000-a11a0ce2-ea20-4897-a713-130a6538cd9a-c000.snappy.parquet
sales/year=2022/product=002/part-00000-a11a0ce2-ea20-4897-a713-130a6538cd9a-c000.snappy.parquet
...
sales/year=2023/product=500/part-00000-a11a0ce2-ea20-4897-a713-130a6538cd9a-c000.snappy.parquet
Эту структуру я придумал с головы. Но у вас есть много вариантов как комбинировать продукты-менеджеры-заказчики-отчетные-периоды.
И есть предположение что в таком случае операции агрегации
пройдут быстрее за счет естесвтенного физического партишеннга. (Это я говорю для Spark. Для его оптимизатора. Как будет в Panadas я не знаю.)
С точки зрения Spark - структура файлов в таком формате рассматривается как партицированная табличка в оракле. При этом надо конечно помнить основные правила HDFS и биг-дата.
Никаких мелких файлов! Вы должны расчитывать в 128Мб как в самую мелкую единицу I/O.
Пятое. Я это не использовал. Но
посмотрите в направление библиотеки Apache Arrow. Она имеет сильные оптимизации для векторной алгебры и знает в лицо parquet. Если вы все-таки хотите оставаться в той парадигме выдачи запросов Python/Django/Pandas - то исследуйте как arrow может ускорить ваши операции агрегаций. Только вам возможно придется отказаться от Pandas-DataFrame API а использовать что-то низкоуровневое типа С++ для векторизовнного API.
Как видите - векторов развитя много. Думайте.
UPD: