Я хочу отслеживать счетчик пользователей, хотя время и иметь возможность генерировать статистику об изменениях в счетчике через время.
Я довольно настроен (хотя, если они лучше, я хотел бы услышать о них) о двух основных таблицах. user и counter_change, который будет выглядеть примерно так:
user:
+-----------+------------+
| id | username |
+-----------+------------+
| 1 | foo |
| 2 | bar |
+-----------+------------+
counter_change:
+-----------+--------------------+------------+
| user_id | counter_change_val | epoch_time |
+-----------+--------------------+------------+
| 1 | 10 | 1513242884 |
| 1 | -1 | 1513242889 |
+-----------+--------------------+------------+
Я хочу, чтобы показать текущее значение счетчика (с базовым значением 0) во внешнем интерфейсе, а также некоторые статистические данные через время (например: вчера ваш сетевой счетчик был +10 или -2 и т.д.).
Я подумал о некоторых возможных решениях, но ни один из них, похоже, не является идеальным решением.
user
(или в таблицу новых counters
): Это решение кажется более эффективным с точки зрения ресурсов, во время ввода counter_change, обновлять счетчик у user
с помощью counter_change_val.
Получить текущее значение счетчика не потребует практически никаких ресурсов.
Сумма counter_changes_val может отклоняться от счетчика в user
если возникает ошибка.
Не может быть действительно использован для полей статистики, поскольку для этого потребуется дополнительный запрос, и в этот момент триггер будет более удобен.
user
(или в таблицу новых counters
) в insert/update:Это решение состояло бы из триггера SQL или некоторой функции на уровне ORM, которая обновляла бы значение вставки в таблице counter_change с суммой counter_change_val.
Это также будет использоваться для вычисленных полей, которые предполагают группировку по датам. Например, получите среднесуточные изменения за последние 30 дней.
Получить текущее значение счетчика не потребует практически никаких ресурсов.
В каждой вставке counter_change
агрегация всего текущего пользовательского counter_change
.
Это решение будет состоять из создания представления или выбора для получения суммы совокупного counter_change_val, когда это необходимо.
Не добавляет полей в таблицы.
Поскольку он вычисляется во время выполнения, он добавляет время для запроса времени отклика. При каждом обращении к счетчику потребуется скопировать значения counter_change.
На самом деле, я не уверен, что понял то, что вы пытаетесь сделать. Тем не менее я бы предложил вариант 1 или вариант 2:
Вариант 1 эффективен, и он достаточно безопасен для ошибок, если это делается правильно. Например, вы можете обернуть вставку counter_change и вычислить новое значение counter_value в транзакции; это предотвратит любые несоответствия. Вы можете сделать это либо в фоновом программном обеспечении, либо в триггере (например, при вставке counter_change).
Что касается варианта 2, мне непонятно, зачем понадобится агрегация по всему счетчику текущего пользователя. Вы можете отрегулировать значение counter_value в таблице пользователя из триггера вставки, как в варианте 1, и вы можете использовать транзакции, чтобы сделать его безопасным.
ИМХО, корректируя текущее значение counter_value при каждой вставке counter_change, является наиболее эффективным решением. Вы можете сделать это либо в фоновом программном обеспечении, либо внутри триггера. В обоих случаях используйте транзакции.
Вариант 3) не следует использовать, потому что он загрузит большую часть нагрузки в систему (предположим, что у вас 1000 счетчиков_пользователя на пользователя...).
Что касается статистики: это другая проблема, связанная с хранением данных в первую очередь. Вероятно, вам понадобится какая-то агрегация для любых статистических данных. Чтобы ускорить это, вы могли бы подумать о кешировании результатов и тому подобных вещах.