Объединить три таблицы в одну или слишком много столбцов? - PullRequest
1 голос
/ 20 июля 2010

Я отслеживаю клики за три периода времени: прошедший день, прошедшую неделю и прошедший месяц.

Для этого у меня есть три таблицы:

  • Anпочасовая таблица, со столбцами link_id, двумя другими атрибутами и от часа_1 до часа_24, вместе с вычисляемым столбцом, дающим сумму

  • Таблица дня недели, со столбцами click_id, двумя другими атрибутами и day_1до дня_7 вместе с вычисляемым столбцом, в котором указана сумма

  • Таблица месяца, как указано выше, со столбцами от дня_1 до дня_31

При нажатииЯ сохраняю его ключевые атрибуты, такие как href, description и т. д., в других таблицах и вставляю или обновляю строку (и), соответствующую link_id в каждой из приведенных выше таблиц.

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

Таким образом, если пользователь имеет тип A и сидит в X, в вышеприведенных таблицах создаются или добавляются три строки - первая строка записывает все клики по этой ссылке за период времени, вторая строка записывает всеклики "Люди типа" и третий "Все клики людей в X".

Я разработал его таким образом, поскольку не хотел перемещать данные каждый час / день / неделю / месяц.Я просто поддерживаю указатели для «текущего часа» (1-24), «текущего дня» (1-31) и «текущего дня недели» (1-7) и записываю соответствующие ячейки в таблицах.Когда мы вводим новый период (например, «15:00 - 16:00»), я могу просто очистить этот текущий столбец (например, hour_15), а затем начать увеличивать его для ссылок по мере их поступления. Время от времени я могу удалять старые строки, которые выпаливплоть до «все ноль».

Таким образом, мне никогда не придется перемещаться по столбцам, что, вероятно, будет очень дорого для потенциально десятков тысяч строк.

Я буду выбирать только строки текущего дня / дня недели / часа (до вставки / обновления) или ТОП-20 значений из вычисленных столбцов на основе атрибутов (и, скорее всего, буду кэшировать эти результаты в течение часа или около того).

После заполнения таблиц UPDATES намного превысят INSERT, так как уникальных hrefs не так много.

Три вопроса:

  • Можно ли комбинироватьтри большие таблицы в одну большую таблицу дней / будней / часов?Это дало бы таблицу с 64 столбцами, что, я не уверен, является излишним.С другой стороны, если держать их отдельно, как сейчас, то утроим количество необходимых операторов INSERT / UPDATE.Я не знаю достаточно о сервере SQL, чтобы знать, какой из них лучше.

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

  • Что касается дизайна, очевидно, что существует некоторая избыточность в том, чтобыкак по будням, так и по месяцам.Однако это был единственный способ сохранить указатель на столбец, быстро обновить его и использовать вычисляемый столбец.Если бы я исключил таблицу дней недели, мне нужно было бы получить дополнительный вычисляемый столбец для «дней месяца», которые суммировали предыдущие 7 дней - (например, если сегодня 21-е число, то сумма day_14, day_15, day_16 ... day_20).Расчет придется обновлять каждый день, что я думаю, будет дорого.Отсюда дополнительная таблица «будний день» для простого статического расчета.Я ценю простые и быстрые вычисления выше, чем небольшие хранилища данных.

Заранее спасибо!

Ответы [ 3 ]

4 голосов
/ 20 июля 2010

Каждый раз, когда вы видите столбцы с номерами в их именах, такие как column_1, column_2, column_3 ... ваш флаг «ужасного дизайна базы данных» должен подниматься. (К вашему сведению, здесь вы нарушаете 1NF, в частности, вы повторяете группы по столбцам )

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

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

CREATE TABLE base_stats ( link_id INT, click_time DATETIME )
CREATE TABLE daily_stats ( link_id INT, period DATETIME, clicks INT )

Вы всегда можете агрегировать с

SELECT link_id, count(*) as clicks, DATE(click_time) as day
FROM base_stats
GROUP_BY link_id, day

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

Приведенный выше дизайн намного чище для будущего специального анализа (произойдет со статистикой). Другие преимущества смотрите в википедии о повторяющихся группах.

EDIT: Хотя решение с двумя таблицами base_stats и aggregated_stats принято, со следующей стратегией:

  • вставлять каждый клик в base_stats
  • периодически агрегирует данные из base_stats в daily_stats и очищает все детали

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

CREATE TABLE period_stats ( link_id INT, period DATETIME, ...)

Обновление легко с

UPDATE period_stats 
SET clicks = clicks + 1 
WHERE period = @dateTime AND link_id = @url AND ...

Стоимость обновления этой таблицы при правильной индексации столь же эффективна, как и вставка строк в base_table, и любую ее также легко использовать для анализа

SELECT link_id, SUM(clicks)
FROM period_stats
WHERE period between @dateTime1 AND @dateTime2
GROUP BY ...
3 голосов
/ 20 июля 2010

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

2 голосов
/ 20 июля 2010

Этот дизайн действительно плохой.Предложение Unreason лучше.
Если вы хотите сделать его красивым и легким, вы также можете иметь одну таблицу с 2 полями:

   timeSlice  
   clickCount  
   location
   userType 

с TimeSlice, в котором дата и время округлены до часа,Все остальное можно вычесть из этого, и у вас будет только
24 * 365 * местоположений # * типов #
записей в год.

Всегда в зависимости от конфигурации и осуществимости, с этой таблицейдизайн, вы можете в конечном итоге накапливать значения в памяти и обновлять таблицу только один раз в 10 секунд.или в любое время <= 1 час, в зависимости от приемлемого риска </p>

...