Сохранить 2-мерную таблицу посещаемости в базе данных? - PullRequest
0 голосов
/ 03 октября 2009

У нас есть веб-приложение, поддерживаемое базой данных MySQL.

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

Мне было интересно, как лучше всего хранить это в базе данных?

В настоящий момент, человек, работающий над этим, склоняется к тому, чтобы сохранять это как одно целое для каждого дня, где 1 представляет посещаемость, а 0 - не посещает. Я думаю, что значит использовать битовую маску (например, 13 для 1101, поэтому каждый сеанс кроме полудня). Они просто хранят его как «0» и «1» по какой-то странной причине.

Я подумал, что может быть проще сохранить его в виде списка bools (бит / крошечные), например monday_morning, monday_lunch, monday_affter и т. д., поскольку это семантически более «правильно» (я думаю?), вероятно, его будет легче расширять / поддерживать, и я также, кажется, единственный в команде, кто знает, как делать битовые операции ... LOL.

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

Какие рекомендации по этому поводу? Или есть лучшие способы хранения этих данных?

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

Ура, Victor

Ответы [ 2 ]

1 голос
/ 03 октября 2009

Я бы нормализовал его и имел три таблицы: users, session и session_attended. Пользователи будут содержать информацию о пользователе, сеансы будут содержать информацию о сеансе, а session_attended будет таблицей соединений, указывающей, какие сеансы посещал пользователь. Правильно индексируйте свои таблицы, и полученные объединения должны быть довольно эффективными.

 select users.name, sessions.name
 from users u join sessions_attended a on u.user_id = a.user_id
      join sessions s on s.session_id = a.session_id
 where sessions.course = ...some course id...
0 голосов
/ 03 октября 2009

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

И не храните bit внутри. Вы не увидите никакого уменьшения объема памяти, скажем, tinyint (движок не собирается выделять для вас ровно один бит, он просто ограничивает допустимые значения). Вы также можете использовать tinyint и дать себе немного места для дыхания.

Редактировать

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

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

  2. Полностью нормализованное решение усложнит запросы данных. Хотя он будет поддерживать индексацию, для каждого типа сеанса, который вы хотите проверить, потребуется полное объединение.

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

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