Подтвердить что ты не робот

Флаги в строках базы данных, лучшие практики

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

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

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

Итак, что такое "правильный" способ сделать это?

4b9b3361

Ответ 1

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

Однако, если эффективность пространства является серьезной проблемой, а функция запроса - нет, то беззнаковая маска будет работать почти так же.

Ответ 2

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

Реляционное решение было предложено ранее. Учитывая пример, который вы указали, я бы создал что-то вроде этого (в SQL Server):


CREATE TABLE Users (
  UserId INT IDENTITY(1, 1) PRIMARY KEY,
  FirstName VARCHAR(50),
  LastName VARCHAR(50),
  EmailAddress VARCHAR(255)
);

CREATE TABLE Badges (
  BadgeId INT IDENTITY(1, 1) PRIMARY KEY,
  [Name] VARCHAR(50),
  [Description] VARCHAR(255)
);

CREATE TABLE UserBadges (
  UserId INT REFERENCES Users(UserId),
  BadgeId INT REFERENCES Badges(BadgeId)
);

Ответ 3

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

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

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

Ответ 4

Очень реляционный подход

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

например. для таблицы "Студенты" вы могли бы иметь таблицы "RegisteredStudents", "SickStudents", TroublesomeStudents и т.д. Каждая таблица будет иметь только один столбец: student_id. Это будет очень быстро, если все, что вы хотите знать, это то, что учащиеся "зарегистрированы" или "больны", и будут работать одинаково в каждой СУБД.

Ответ 5

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

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

CREATE TABLE ... (
    warnings INTEGER,
    errors   INTEGER,
    ...
)

вы должны использовать:

CREATE TABLE ... (
    warning_foo BOOLEAN,
    warning_bar BOOLEAN,
    warning_...
    error_foo   BOOLEAN,
    error_bar   BOOLEAN,
    error_...   BOOLEAN,
    ...
)

Хотя MySQL не имеет типа BOOLEAN, для этой цели вы можете использовать квазистандартный TINYINT (1) и установить его только в 0 или 1.

Ответ 6

Если в будущем существует больше, чем несколько флагов или, вероятно, будет так, я буду использовать отдельную таблицу флагов и таблицу "многие-ко-многим" между ними.

Если есть несколько флагов, и я никогда не буду использовать их в WHERE, я буду использовать SET() или битовое поле или что-то еще. Они просты в чтении и более компактны, но боль в запросе, а иногда даже больше от головной боли с ORM.

Если есть только несколько флагов - и только когда-либо будет несколько флагов, тогда я просто сделаю пару BIT/BOOLEAN/etc.

Ответ 7

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

В противном случае наилучшим подходом будет использование NUMBER (1) или эквивалент, и установите ограничение проверки на столбец, который ограничивает допустимые значения (0,1) и, возможно, NULL, если вам это нужно. Если нет встроенного типа, использование числа менее неоднозначно, используя столбец символов. (Какое значение для true? "T" или "Y" или "t" )

Приятная вещь в том, что вы можете использовать SUM() для подсчета количества ИСТИННЫХ строк.

SELECT COUNT(1), SUM(ActiveFlag)
FROM myusers;