Каков наилучший способ оптимизации схемы для сбора данных о посещаемости - PullRequest
3 голосов
/ 07 июля 2010

У нас есть спортивный тренировочный лагерь, в котором регулярно принимают участие различные команды города. У нас есть сеанс в день, продолжающийся 2 часа (9-11 утра), и временные интервалы могут отличаться для разных команд. Мы хотели бы узнать, кто посещал тренировочный лагерь ежедневно.

Мы пришли к следующей модели, чтобы захватить посещаемость. (id, user_id, date, present). Предполагая, что пользователь посещает лагерь ежедневно (скажем, 30 дней в месяце), вы увидите столько записей в базе данных.

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

Ответы [ 4 ]

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

Вы используете слово «оптимизировать» в заголовке вопроса, не объясняя что именно вы хотите оптимизировать .

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

Вы упомянули электронные таблицы в одном из ваших комментариев. Это неплохой дизайн. В верхней строке расположены сеансы, внизу - команды, а ячейки показывают, присутствовала ли команда на сессии. Они сопоставляются с тремя таблицами базы данных: SESSIONS, TEAMS и таблицей пересечений TEAM_SESSIONS. Вам нужна запись в TEAM_SESSIONS только когда команда присутствовала на сессии.

В качестве подтверждения концепции я разбил три таблицы в Oracle.

SQL> desc teams
 Name                                      Null?    Type
 ----------------------------------------- -------- ----------------------------
 ID                                        NOT NULL NUMBER
 NAME                                               VARCHAR2(20 CHAR)

SQL> desc sessions
 Name                                      Null?    Type
 ----------------------------------------- -------- ----------------------------
 ID                                        NOT NULL NUMBER
 SSN_DAY                                            DATE
 SSN_START                                          NUMBER(4,2)
 SSN_END                                            NUMBER(4,2)

SQL> desc team_sessions
 Name                                      Null?    Type
 ----------------------------------------- -------- ----------------------------
 TEAM_ID                                   NOT NULL NUMBER
 SESSION_ID                                NOT NULL NUMBER

SQL>

Функция PIVOT, появившаяся в Oracle 11g, позволяет легко разбить матрицу (разные варианты СУБД будут по-разному подходить к этому). Как вы можете видеть, три команды забронировали сессию сегодня, никто не хочет тренироваться во время обеда, и Бек Юнайтед увлечен горчицей (или нуждается в обучении)!

SQL> select * from (
  2      select t.name as team_name
  3             , trim(to_char(s.ssn_start))||'-'||trim(to_char(s.ssn_end)) as ssn
  4             , case when ts.team_id is not null then 1 else 0 end as present
  5      from   sessions s
  6             cross join teams t
  7             left outer join team_sessions ts
  8                  on (ts.team_id = t.id
  9                      and ts.session_id = s.id )
 10      where s.ssn_day = trunc(sysdate)
 11      )
 12  pivot
 13      ( sum (present)
 14        for ssn in ( '9-11', '11-13', '13-15', '15-17', '17-19')
 15      )
 16  order by team_name
 17  /

TEAM_NAME                '9-11'    '11-13'    '13-15'    '15-17'    '17-19'
-------------------- ---------- ---------- ---------- ---------- ----------
Balham Blazers                0          1          0          0          0
Bec United                    1          0          0          0          1
Dinamo Tooting                0          0          0          0          0
Melchester Rovers             0          0          0          1          0

SQL>

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

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

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

Вы должны спросить себя, почему вы это сделали.

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

Итак, прежде всего:Чего вы хотите достичь и каковы причины этого?

Некоторые возможности:

  • Некоторые СУБД предоставляют возможность создавать пользовательский тип
  • Вы можете использовать побитовый подход (в mysql самый простой способ для этого - использовать тип данных SET )

Но опять же: какова ваша текущая проблема, поскольку выяснение количествадни, когда кто-то присутствовал, были не чем иным, как объединением соответствующих таблиц и объединением их с функцией подсчета

1 голос
/ 07 июля 2010
AttMst
  id | date

AttDet
  attdetid | id | userid

Таким образом, вам нужно сохранить день в AttMst, а нынешние пользователи в этот день будут сохранены в AttDet.

0 голосов
/ 07 июля 2010

ИМХО, наличие одной строки на пользователя в месяц с большим количеством сцепленных символов не будет лучше, чем наличие множества строк с одним символом, особенно если вам придется разделить этоСтрока каждый раз, когда вы хотите отобразить данные в другом приложении.

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

Итак, мой совет будет состоять из двух таблиц:

id | user_id | date | present

и

user_id | month | attendance

У вас также должно быть несколько индексов для поля user_id, чтобы повысить производительность системы.

Cheers

...