Комментарии 30
Не пробовали https://github.com/lazada/sqle?
Ее под большую нагрузку и выборки делали.
У меня пока получалось, что решения с Reflect получались только на несколько процентов медленнее аналогичного решения с кодогенерацией, если стараться этот самый Reflect кэшировать.
Но кешировать Reflect — вполне здравая идея. Это уже относится к задаче оптимизации работы с ним, которая появляется от того, что всё-таки там есть что ускорять. Я сам его использовал раз в месте которое выполнялось один раз при инициализации. Там можно не задумываться об оптимизациях. Но вот если в цикле на миллион шагов — тут уже я бы подумал про его применение.
Но не думаю что именно эта библиоетека хоть как то решает проблемы производительности
Доброго дня, коллега!
В product service нам она дала разницы до 8x по сравнению со стандартной.
Для примера я оставил только 5 объектов. Их на самом деле больше. Есть ещё связки типа баннер-кампания. Есть связки через дополнительные поля, которые в других таблицах. В итоге если делать 10 запросов GROUP BY подряд с INSERT'ом в таблицы статистики — мы нагрузим MySQL, залочим таблицы. Плюс есть ещё особая логика подсчета дополнительных параметров — я её выбросил для чистоты експеримента. Ну и в планах делать антифрод по прошествии суток — там уже на SQL никак не провести анализ — нужны деревья.
Язык Go, как мне кажется, больше подходит для работы с большими наборами данных. Проблема в универсальных драйверах БД, которые стремясь угодить программисту, дают оверхед на конвертацию пришедшего из базы туда-сюда-обратно. Вот я и выяснил для себя какая связка дает большую скорость, далее, видимо, закодирую её в каких-то функциях, чтобы перевести остальную часть проекта на более производительные SELECT-ы. Ну и решил поделиться с сообществом, ибо такие задачи для Go должны возникать в любом серьезном проекте.
Тупиковый путь, имхо. Забирать все данные из базы, что бы потом обработать их на Go. И пересчет статистики ночью — тоже. Часто статистика нужна в реальном времени (с задержкой в пять минут, а не ночь). Хорошо, если вам пока хватает раз в сутки.
Но допустим вам надо вычесть из статистики фрод-показы и актуализировать вчерашние данные. Как тогда быть?
Для сложной логики вам виднее. Если без получения полных данных никак, значит никак. Но и здесь направление "раз в сутки" выглядит не очень хорошо — ведь сутки у всех заканчиваются в разное время. То, что для вас — ночь, для других — разгар дня.
И поставлю +1 за кликхаус, будет интересно почитать, если напишите результаты вашего тестирования.
В итоге если делать 10 запросов GROUP BY подряд с INSERT'ом в таблицы статистики — мы нагрузим MySQL, залочим таблицы.
Зачем? Просто выбрать с GROUP BY, а дальше то же самое, просто не someCounter.Inc(someId)
, а someCounter.Add(someId, someCount)
.
И скорость выборки 36 секунд для почти 56 миллионов записей.
56 миллионов записей, по 5 4-байтовых интов в каждой, 56M*20 = 1120M, больше гигабайта. Мне кажется, основное время уходит на передачу данных, а конвертация занимает копейки.
Плюс GROUP BY на MySQL не такой шустрый, например
SELECT campaignID, COUNT(*) FROM hit_20180507 GROUP BY campaignID
Занимает 8,6 секунд на этом сервере на прогретых данных. А группировка по двум полям уже 12,9 секунд.
36 секунд я путем манипуляций превратил в 27 секунд. И судя по профилировщику — там можно выжать ещё пару секунд, убрав ненужные конвертации через строку. Данные находятся на localhost-сервере, 5 Гб на диске SSD, ещё и в кеше. Думаю сама передача занимает секунд 10.
Проверил — оставил цикл
for rows.Next() {
c++
}
итог — 11.9 секунд. Остальное время тратится на доступ к хеш-мапам, ну и конечно же на Scan.
36 секунд я путем манипуляций превратил в 27 секунд.
9 секунд на 56 миллионов итераций. Если итераций будет меньше, то и экономия будет не такая заметная. Но согласен, я слишком преувеличил.
Делать потом ещё 10 запросов?
Да. Можно сделать один с GROUP BY по всем параметрам, остальное в приложении досчитать. Счет строк будет на тысячи, а не на миллионы. Но судя по цифрам это не подходит. Хотя все равно многовато как-то.
Если бы я писал обработку этого запроса на PHP, к примеру, я бы тоже постарался уменьшить число строк с помощью БД. Там цикл на сто тысяч уже может показаться «вечным» и оптимизировать что-то как здесь — не представляется даже возможным.
В некоторых случаях после group by количество строк будет примерно равно количеству до (может в разы сократится, но не в десять). Рекламная сеть, как раз такой случай там каждый второй клик может быть уникален с точки зрения набора группировочных параметров.
А если просто взять clickhouse? Я использую для мгновенных выборок из сотен миллионов даных. Можно еще использовать ProxySQL https://github.com/sysown/proxysql/wiki/ClickHouse-Support
Go: ускоряем выборку больших таблиц из MySQL