7 ноября 2011 г.

Хранение булевых полей в базе данных

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

Итак, идея достаточно проста. Каждое целое число, которое является степенью двойки, имеет уникальную единицу в соответствующем этому числу месте. Поясню на Python:

>>> for i in range(9):
        p = pow(2, i)
        print '%d\t%11s' % (p, bin(p))

 
1           0b1
2          0b10
4         0b100
8        0b1000
16      0b10000
32     0b100000
64    0b1000000
128  0b10000000
256 0b100000000

Т.е. всем необходимым булевым значениям мы сопоставляем целое число степени двойки отличное от нуля. К примеру:

CHOICES = (
    (1,  'Значение 1'),
    (2,  'Значение 2'),
    (4,  'Значение 3'),
    (8,  'Значение 4'),
    (16, 'Значение 5'),
    (32, 'Значение 6'),
    (64, 'Значение 7'),
    # etc
)

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

Организовать совокупность полей можно битовым оператором |, т.е.

>>> 1|2
3
>>> 4|16|64
84

А проверить булевый флаг можно так:

>>> bool(84&16)
True
>>> bool(84&64)
True
>>> bool(84&4)
True
>>> bool(84&0)
False
>>> bool(84&32)
False

Надо сказать, что работать с целыми числами программы будут гораздо быстрее, чем со строками. И битовые операции быстрее обычных. Так что и здесь преимущества.

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

Комментариев нет:

Отправить комментарий