2010-07-07 2 views
3

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

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

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

ответ

1
AttMst 
    id | date 

AttDet 
    attdetid | id | userid 

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

+0

am, поворачиваясь к этой модели. как бы вы запрашивали все записи посещаемости пользователей в течение месяца? Как бы вы присоединились к таблице AttMst? – Sam

+1

'select date, userid from AttMst am, объявление AttDet, где am.id = ad.id group by date. Это будет отображаться по дате. Но это непроверенный запрос, пожалуйста, проверьте его. – Himadri

0

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

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

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

id | user_id | date | present 

и

user_id | month | attendance 

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

Cheers

+0

Предполагая, что вторичная таблица будет использоваться для увеличения или уменьшения при каждом значении. Поэтому вы советуете против механизма count (*) прийти к общему количеству дней, когда игрок присутствовал. Я прав? – Sam

+1

Yup, в основном потому, что это может вызвать проблемы с производительностью. Но если у вас быстрый сервер или вы не ожидаете большого количества пользователей, тогда механизм подсчета прекрасен. В любом случае, забудьте о конкатенации. –

2

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

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

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

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

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

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

+0

Согласен, достаточно одного стола. Сервер базы данных работает быстро, поэтому нет необходимости денормализовать. – mb14

+0

@ mb14 Но когда есть большой объем данных, будет полезно нормализовать данные. – Himadri

+0

Я не был уверен, нужно ли нам много строк для сбора информации о посещаемости (если вы посмотрите на лист Excel с такой информацией, это похоже на сетку, и у вас есть набор значений за весь месяц против пользователя, все дни в месяц). Я пытался это моделировать. Я согласен с тем, что было бы болезненно отметить присутствие или отсутствие игрока в этом списке, разделенном запятыми – Sam

2

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

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

Вы упомянули электронные таблицы в одном из своих комментариев. Это не плохой дизайн. В верхней строке есть сеансы, в стороне есть команды, а ячейки показывают, присутствовала ли команда на сеансе. Они сопоставляются с тремя таблицами базы данных: СЕССИЯМИ, ТИПАМИ и таблицей пересечений 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 делает его подпруга, чтобы сколотить матрицу (различные ароматы СУБД будут иметь разные способы приблизиться к этому). Как вы можете видеть, три команды сегодня забронировали сеансы, никто не хочет тренироваться в обеденное время, а Bec United - как горчица (или нужна тренировка)!

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 - не лучшая идея.