Где или как хранить большие объемы данных (python + mysql)

В общем пишу систему учета кликов/показов для баннеров. я в бд записываю дату, ip, тип (показ/клик). Предполагается размещать на сайте, где более 40000 просмотров, соответственно при 2-3 баннерах это более 100000 записей в день. как такие объемы хранить?

думаю сделать таблицу, где буду считать общее кол-во за день - пока вижу только этот вариант.

1 ответов


Для таких случаев идеально подходит секционирование таблицы. Делаете одну большую таблицу, разбиваете на секции типа Range по дате. Период партицирования зависит от объема и логики дальнейших расчетов: идеально было бы 1 день - 1 секция, но можно разбить и по часу или еще как-то. Если секции все-равно большие, можно добавить субпартиции (подсекции) типа List по ID баннера.

В самой таблице никаких автоинкриментов, ключей, индексов, констрейнтов ("NOT NULL" и т.п.) делать не надо. Обеспечьте чтобы приложение, а не база занималась проверками данных. Тогда вставка записи будет происходить максимально быстро.

Теперь можно динамично лопатить большие объемы данных. Регулярно по крону или еще как-то должны добавляться новые партиции на завтра. Если будете делать субпартиции, при добавлении новых баннеров нужно оперативно менять шаблон партицирования, иначе будут фейлы вставки. Обратите внимание, новые субпартиции появятся только в новой партиции. В это время строки пишутся в сегоднешнею.

Данные, собранные в одной секции - вся история за день. По прошествии суток можно неспеша запустить запрос с каунтом и группировкой (тут очень помогут субпартиции - они работают лучше индекса). Обсчитать все что нужно, сохранить в другой, сводной таблице и затем alter table drop partition - через секунду от гигабайт данных не осталоь и следа.


бОльшая часть проектов в которых мне удалось поучаствовать хратит такую информацию в текстовых файлах. Потому что скорость добавления - очень важный параметр. Файлы обычно посуточные. В особо тяжелых случаях - почасовые. Далее некий скрипт на кроне периодически считает по этим логам обобщенную статистику а сами логи либо архивирует, либо удаляет.
А вот конкретно в проекте, над которым работаю в данное время, логи кликов пишутся в mysql таблицу. Объемы - сравнимые с Вашими. Таблица, естественно без всяких индексов. Иначе добавления неприлично нагрузят сервер.
Раз в неделю таблица дампится и суммируется с предыдущими данными в другую базу данных, на другую машину. Там уже рисуются индексы и по той таблице идет обсчет. Исходная таблица обрезается до нулевого размера, и цикл повторяется по-новой. не сказать, что это очень оптимальный способ, текстовый файл все же выгоднее. Но железо позволяет в данном конкретном случае выпендриться :) Дело в том, что по спецификации нам детальную инфу по кликам нужно хранит три года. Храним в отдельной базе на отдельной машине в таблицах по годам-месяцам. Там и обсчитываем, там и отчеты делаем.
Но по фен-шую все же лучше текстовые файлы. Во всех отношениях лучше.


Под большие объёмы таких несвязных данных (а просмотров планируется много, да?) я бы рекомендовал отказаться от реляционных БД и смотреть в сторону NOSQL. Тот же MongoDB покроет вашу нагрузку с полпинка:

  • Резкие инсерты и апдейты.
  • Асинхронные запросы по дефолту (вам самое то, ибо не сильно критично потерять пару просмотров из 100 тысяч).
  • Кластеризация из коробки (если таки упрётесь в производительность одного сервера).
  • MapReduce спасает при агрегировании показов по суткам.

Наверное лучше будет вообще отдельную БД под это дело сделать. Конечно для приложения будет дополнительной нагрузкой подключение еще к одной БД - но думаю это нивелируется при очень больших объемах. Дополнительные плюсы - при разрастании сайта базу со статистикой без проблем можно будет перенести на отдельный сервер.
Еще вариант - создавать новую таблицу в БД через определенные периоды времени (сами периоды высчитываем эмпирическим путем - когда размер таблицы приближается к ограничению по размеру ). Имена таблиц в этом случае привязываем к этим периодам, чтобы наше приложение смогло определить, откуда брать записи при получении статистики.

Ваш вариант с одной стороны прост - пишем только ID банера и инкрементим количество кликов/показов, и если такой статистики хватит то в принципе нормально. Только следует учесть - при таком количестве показов может возникнуть проблема с одновременным доступом к записи.


В одном проекте была схожая задача. Была решена так:
Подсчет показов / кликов ведется insert'ом в таблицу (mysql). Каждые 24 часа выполняется скрипт, который выбирает count показов и кликов из этой таблицы, группируя их по id баннера, и записывает из в другую таблицу. Скрипт может выбирать данные порционно, скажем, удаляя те записи, которые были обработаны, с лимитом в 10 записей (помните, что скрипт делает выборку с group by).