Каков наилучший способ реализовать счетчик поля в MySQL? - PullRequest
6 голосов
/ 09 февраля 2009

Я хочу начать подсчет количества просмотров веб-страницы и, следовательно, нужен какой-то простой счетчик. Каков лучший масштабируемый способ сделать это?

Предположим, у меня есть таблица Frobs, где каждая строка соответствует странице - некоторые очевидные варианты:

  1. Есть поле без знака int NumViews в таблице Фробс, которая получает обновляется при каждом просмотре с использованием UPDATE Frobs SET NumViews = NumViews + 1. Простое, но не очень хорошее масштабирование, насколько я понимаю.

  2. Есть отдельная таблица FrobViews где новая строка вставляется для каждого представления. Для отображения количество просмотров, то вам нужно сделать простой SELECT COUNT(*) AS NumViews FROM FrobViews WHERE FrobId = '%d' GROUP BY FrobId. Это не требует каких-либо обновлений, поэтому можно избежать блокировки таблиц в таблицах MyISAM - однако производительность чтения снизится, если вы захотите отобразить количество просмотров на каждой странице.

Как ты это делаешь?

Здесь есть несколько полезных советов: http://www.mysqlperformanceblog.com/2007/07/01/implementing-efficient-counters-with-mysql/ но я бы хотел услышать мнение сообщества SO.

В настоящее время я использую InnoDb, но меня интересуют ответы как для InnoDb, так и для MyISAM.

Ответы [ 4 ]

3 голосов
/ 14 апреля 2011

Вставка в базу данных - это не то, что вы хотите делать при просмотре страниц. Скорее всего, у вас возникнут проблемы с обновлением подчиненных баз данных всеми вставками, поскольку репликация в MySQL однопоточная.

В моей компании мы обслуживаем 25 миллионов просмотров в день, и мы выбрали многоуровневый подход.

Счетчик представлений хранится в отдельной таблице с 2 столбцами (profileId, viewCounter), оба являются целыми числами без знака.

Для элементов, которые просматриваются редко, мы обновляем таблицу при просмотре страницы. Для часто просматриваемых товаров мы обновляем MySQL примерно в 1/10 времени. Для обоих типов мы обновляем Memcache при каждом попадании.
int Memcache::increment ( string $key [, int $value = 1 ] )

if (pageViews < 10000) { UPDATE page_view SET viewCounter=viewCounter+1 WHERE profileId = :? }

else if ((int)rand(10) == 1) { //UPDATE page_view SET viewCounter= ?:cache_value WHERE profileId = :? }

Выполнение count (*) в InnoDB очень неэффективно (MyISAM сохраняет статистику счетчика в индексе), но MyISAM заблокирует таблицу при чтении, уменьшая параллелизм. выполнение count () для 50 000 или 100 000 строк займет много времени. Выполнение выбора на ПК будет очень быстрым.

Если вам требуется больше масштабируемости, вы можете посмотреть на redis

3 голосов
/ 09 февраля 2009

Если для вас важнее масштабируемость, чем абсолютная точность цифр, вы можете на короткое время кэшировать счетчик просмотров в вашем приложении, а не попадать в базу данных при каждом просмотре страницы - например, обновлять базу данных только один раз каждые 100 просмотров. .

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

2 голосов
/ 09 февраля 2009

Я бы взял ваш второй подход и собирал данные в таблицу из вашего первого решения на регулярной основе. На этом пути вы получаете преимущества обоих решений. Чтобы быть понятнее: При каждом попадании вы вставляете строку в таблицу (назовите ее hit_counters). Эта таблица получила только одно поле (pageid). Каждые x секунд вы запускаете скрипт (с помощью cronjob), который объединяет данные из таблицы hit_counters и помещает их во вторую таблицу (назовем ее 'hit'. Там у вас есть два поля: pageid и total hit. *

Я не уверен, но imho действительно не помогает innodb для решения 1, если вы получаете много обращений на одну и ту же страницу: Innodb блокирует строку во время обновления, поэтому все другие обновления в этой строке будут отложены.

В зависимости от того, что написано в вашей программе, вы также можете пакетировать обновления вместе, считая их в приложении и обновляя базу данных только каждые x секунд. Это будет работать, только если вы используете язык программирования, в котором у вас есть постоянное хранилище (например, сервлеты Java, но не PHP)

0 голосов
/ 09 февраля 2009

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

Если вы не используете SP, (или если на вашей странице нет данных базы данных), эта опция может быть недоступна для вас, но если вы ее используете, то стоит подумать.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...