Недостатки использования целого числа в качестве битового поля?

У меня есть куча логических параметров для таких вещей, как «приемлемые типы платежей», которые могут включать такие вещи, как наличные, кредитная карта, чек, PayPal и т. д. Вместо того, чтобы иметь полдюжины логических значений в моей БД, я могу просто использовать целое число и назначить каждый способ оплаты целое число, например

PAYMENT_METHODS = (
    (1<<0, 'Cash'),
    (1<<1, 'Credit Card'),
    (1<<2, 'Cheque'),
    (1<<3, 'Other'),
)

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

Почему я это делаю: у меня уже есть около 15 логических значений, разделенных на 3 разных логических «набора». Это уже много полей, и использование 3-х таблиц «многие ко многим» для сохранения набора данных, которые редко изменяются, кажется неэффективным. Использование целых чисел позволяет мне добавлять до 32 флагов в каждое поле без необходимости вообще изменять БД.


person mpen    schedule 16.06.2010    source источник


Ответы (5)


Если бы вы могли ограничить свой вариант использования одним или несколькими наборами значений, которые могут иметь только один бит true за раз, возможно, вы могли бы использовать перечисления в своей базе данных. Вы получите лучшее из обоих миров, поддерживаемых, как заметки btreat, и еще меньше (и проще), чем несколько логических значений.

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

Некоторые комментарии к перечислениям/битовым полям в Django

person dimo414    schedule 16.06.2010
comment
(1) Как я могу использовать перечисление? Перечисление хранит один из нескольких вариантов (вспомните переключатели), а не несколько флагов (вспомните флажки). (2) Тег Django == не так много контроля над тем, какой тип данных используется. - person mpen; 17.06.2010
comment
Извините, я не знал, что вам нужен этот дополнительный контроль. В вашем примере (тип оплаты) используется радиокнопка, и я ухватился за это. Если вам нужно несколько флагов одновременно, перечисления действительно не будут работать. Я переписал свой ответ. - person dimo414; 18.06.2010
comment
Да... Я думаю, это был плохой пример. В моем случае пользователи могут отметить более одного типа оплаты. Я не уверен, что оболочка битового поля действительно необходима. Я считаю, что работать с битами довольно легко, если вы просто немного подвигаетесь. Однако было бы неплохо, если бы я мог давать имена различным флагам, а не запоминать целые числа. - person mpen; 10.07.2010
comment
Я даю вам чек, потому что вы единственный, кто сказал, что нужно использовать битовое поле, что я в конечном итоге и решил ... хотя я все еще думаю, что это жеребьевка между битовыми полями и отдельными логическими столбцами. На самом деле... логические значения, вероятно, облегчили бы жизнь всем и их было бы легче поддерживать. Но да ладно. мне уже все равно :'( - person mpen; 12.07.2010

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

person btreat    schedule 16.06.2010
comment
Почему данные должны быть перенесены? У вас просто будет неиспользуемый бит, к которому вы больше не получите доступ. - person mpen; 10.07.2010
comment
Мотивация для удаления неиспользуемого поля (независимо от того, представлено ли оно как бит или столбец db) состоит в том, чтобы упростить приложение и, таким образом, улучшить ремонтопригодность. Впрочем, вы совершенно правы. Приложение будет продолжать работать правильно, даже если бит не будет удален. - person btreat; 11.07.2010

Это не самое худшее, но может быть лучший способ.

Определите таблицу под названием PaymentTypes

id, paymentId, key (string), value (boolean)

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

person Byron Whitlock    schedule 16.06.2010
comment
Вы имеете в виду добавить таблицу «многие ко многим» для типов платежей? Я думал об этом... но это дополнительный слой, который на самом деле не кажется необходимым. - person mpen; 17.06.2010
comment
@Mark, на самом деле один ко многим, но это немного хлопотно. У вас также может быть много логических столбцов в таблице с внешним ключом для платежей. - person Byron Whitlock; 19.06.2010
comment
@Bryon: Почему один ко многим? Каждая отгрузка может принимать несколько типов оплаты, и каждый тип оплаты может принадлежать многим отгрузкам = m2m. Следовательно, битовое поле, а не простое перечисление. - person mpen; 19.06.2010


Я думаю, что оба предыдущих плаката были правильными. Самый простой способ сделать это в «реляционной» базе данных — определить новую реляционную таблицу, в которой хранятся типы платежей. Однако на практике это обычно приносит больше хлопот, чем пользы.

Использование перечислений в вашем коде и использование чего-то подобного в БД (проверьте ограничения в Oracle, AFAIK) должно помочь сохранить его поддерживаемым и очевидным для бедняги, чья работа будет состоять в том, чтобы добавить новый тип, много-много лет спустя после того, как вы оставил

person Java Drinker    schedule 17.06.2010