Переваги та недоліки використання бітових масок у базі даних


22

Не так давно я говорив зі своїм колегою, і він напевно був проти використання бітових масок, тому що важко зрозуміти всі значення, які зберігаються в базі даних. На мою думку, не завжди є поганою ідеєю їх використовувати, наприклад, для визначення ролі поточного користувача. Інакше вам потрібно зберігати його в окремій таблиці, що спричинить ще одну ПРИЄДНАЙТЕСЬ. Чи можете ви мені скажіть, чи я помиляюся? Будь-які інші побічні ефекти, переваги / недоліки використання бітових масок?


2
Можливо, буде більше сенсу змусити базу даних створювати бітові маски внутрішньо і представляти вам біти як окремі стовпці. Ваші вимоги можуть змінитися.
Саймон Ріхтер

1
Якщо ви не використовуєте приєднання, ви не використовуєте реляційну базу даних так, як це було призначено.
Пітер Б

Відповіді:


38

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

Якщо ви вже використовуєте реляційну базу даних, це антитіла, яка порушує більшість теорій реляції та всі норми нормалізації. Коли ви будуєте власне сховище даних, це може бути не так вже й поганою ідеєю.

Існує таке поняття, як об'єднується занадто багато таблиць, але для цього впорядковані реляційні бази даних. У багатьох є додаткові можливості, якщо продуктивність стає проблемою: індекси, індексовані перегляди тощо. Навіть якщо значення, які ви шукаєте, змінюються не дуже часто, що є перевагою для Bitmask, головна потреба в управлінні індексуванням є досить легко в базі даних.

Хоча база даних добре справляється з агрегуванням даних, вони можуть стати млявими, коли ви почнете вводити в набори даних такі речі, як складні формули або скалярні функції. Ви можете робити побіжно в своєму додатку, але якщо все, що ви робите, - це отримання пов’язаних даних (пошук ролі користувачів), ви не скористаєтеся тим, що найкраще зберігає ваші дані.

Мій останній аргумент проти цього буде простотою для інших розробників. У вас є користувачі, ролі та завдання. Це набір відносин "багато до багатьох" (оскільки існує декілька відносин), який є настільки поширеним, що ним слід легко керувати. Це просто речі CRUD.


8
Реляційна база даних про найгірше місце для біт-маски. Витрати на зберігання вже не такі вже й погані, що кілька приєднань та додатковий стіл повинні зламати вас. Це, безумовно, робить все важче міркувати. Зберігайте дозволи у вигляді бітів (1/0) у базі даних у власній таблиці та представляйте їх у коді з прапорами, але не. Здається, цілком доречно і здійсненно. Розробники отримують прості прапори, а dbas мають нормалізовані таблиці. Усі раді.
Майк Макмахон

3
Погоджено, я підтримував додаток, який використовував бітові маски для ролей та привілеїв користувача у своїй базі даних. Це був кошмар. Використовуючи 32-бітний int, у нас закінчилося біт, тому хтось мав ідею додати більше бітових масок, а потім із перекриттями, тому біт 4 в одному стовпчику означав біт 8 у цьому іншому стовпці, і вони вийшли з синхронізації. А-а-а-а-а. Індексувати було важко, оскільки індекси зберігають окремі значення стовпців, а не окремі біти в них, тому ви не можете шукати рядки where some_bit_mask & 12 > 0без сканування рядка за рядком.
Брендон

Наприкінці дня вистачило б багато-багато user_role_mapчи user_priv_mapстолу.
Брендон

@MikeMcMahon, чи не могли б ви зануритися глибше у дизайн столу, і як я повинен відобразити його в коді, щоб досягти результату, про який ви говорите?
Олексій Овечкін

2
@usr - Ніколи не кажи ніколи. Звичайно, ви можете використовувати бітові маски, але я б не використовував їх у програмі, що використовує реляційну базу даних. Можливо, є певні крайні випадки, коли ми маємо справу зі застарілими даними або надмірна потреба у швидкості.
JeffO

24

Ви вже назвали відповідні плюси і мінуси:

  • Бітові поля економлять простір.
  • Вони зберігають дані у самій записи, тому для їх пошуку вам не потрібні ПРИЄДНАЙТЕСЬ. (Але окремі поля прапора у записі зробили б те саме.)
  • Вони погано читаються, якщо ви хочете продуктивно працювати з необробленим SQL-висновком.

Щоб вирішити, що робити, потрібно більше інформації:

  • Наскільки дефіцит місця на диску для вашого випадку використання?
  • Ви насправді читаєте ролі користувачів так часто, що час приєднатися до них - це вузьке місце?
  • Чи збираєтесь ви читати вихід SQL і приймати рішення на основі цього - чи це нечитабельна запис бази даних несуттєва, як і той факт, що машинний код вашої системи не читається?

Отже, вам потрібно зібрати фактори ризику, а потім зважити їх, щоб побачити, чи переважують плюси проти мінусів.


Дякую за вашу відповідь, цілком згоден з вашими думками, але загалом це анти-візерунок чи ні? А ви використовуєте маски у своїх проектах?
Алекс Овечкін

12
@Alex Не існує такого поняття, як "найкраща практика", яка б вирішила, що робити у вашому випадку. Якщо у вас дуже мало місця, найкраща практика використання бітових полів. Якщо ви хочете використовувати вихід SQL у звітах перед генеральним директором, використання імен, що говорять, є найкращою практикою. Але ви єдиний, хто знає ці обставини, тому громада не може дати вам рецепт, який завжди діє.
Кіліан Фот

Приймаючи аргумент простору як "химму". Питання про те, чи варто використовувати трохи маску, стоїть або падає на те, чи може вона отримувати якусь користь над і вище.
Роббі Ді

Вам також КОЖНО потрібно обробляти інформацію в базі даних, або вона завжди читається в додатку перед її використанням.
Ян

1
"Чи збираєтесь ви читати вихід SQL і приймати рішення на основі цього - чи це нечитабельна запис бази даних несуттєва, як і той факт, що машинний код вашої системи не читається?" Я думаю, що я не можу говорити для всіх розробників, але коли я розробляю, мені надзвичайно часто починати вибирати дані з БД, щоб щось зрозуміти чи перевірити. Тож я б заперечував, що зазвичай відповідь на це: "Так, хтось буде".
jpmc26

18

Якщо ви дійсно, дійсно , дійсно прив'язали на диск, то ви могли б розглянути растрові зображення для призначених для користувача дозволів. Якщо продуктивність турбує вас, то забудьте про них взагалі, тому що вибирати їх на ділі буде насправді повільніше. Ви не можете значимо індексувати растрове поле, що призводить до сканування таблиці баз даних, які [майже] завжди є вбивцею продуктивності.

Якщо ви не Amazon або Netflix, обсяг даних, що беруть участь у дозволах користувачів, буде незначним порівняно з усім іншим, що вам належить.

Будь-яка серйозна СУБД може впоратися з цим "додатковим приєднанням", навіть не моргаючи.


7
+1: Хороші реляційні бази даних розробляються людьми, які дійсно, справді, дуже добре роблять те, що роблять. Кожен, хто потребує виведення останнього біта продуктивності, який ви можете отримати, використовуючи бітові поля, не потрібно буде задавати це питання. Моделюйте дані, а потім знайдіть частини, які не виконують.
Blrfl

З'єднання зробить код додатка складнішим, тому багато чого зводиться до того, де обробляються ролі.
Ян

4
@Ian мати об'єднання не здається складнішим, ніж необхідність знати, як розшифрувати дозволені маски.
Бред

@Brad, подумайте про перерахунок, який є набором прапора в C #, його значення зберігається "як є" в базі даних, C # cold не може бути простішим. Якщо використовується з'єднання, код C # повинен справлятися зі співвідношенням "1 до багатьох".
Ян

Я також повинен додати, що якщо у вас є кілька булевих стовпців у таблиці, більшість баз даних придумають, як скосити їх на якомога менше місця, і піклуються про біт-подвійність для вас.
Blrfl

8

Коли дороге зберігання було дорогим, благом із бітовими масками було те, що вони економили місце. За часів великих даних це колись не було проблемою.

Беручи до прикладу, який ви наводите - наявність ролей, збережених у вигляді бітової маски, буде щось з запаху коду з точки зору проектування бази даних, оскільки це порушить першу нормальну форму . У цьому сенсі вони є анти-зразком.

При всьому сказаному, це не повинно бути тим чи іншим. Ви можете зберігати дані у вигляді бітової маски, а потім мати вигляд, який може тягнути ролі користувача на льоту. Тоді ви також матимете перевагу з першого погляду перевірити, які користувачі виконували однакові ролі.


2

Єдиною перевагою використання бітових масок є те, що значення бітових полів не є статичним. Реляційні таблиці добре працюють лише в тому випадку, якщо ви заздалегідь знаєте, що записує кожне поле: вам потрібно визначити поля в CREATE TABLEоператорі DDL.

Якщо значення кожного бітового поля налаштовується під час виконання або не відоме достроково, тоді може бути сенсом зберігати булеві як бітове поле. Навіть тоді, можна визначити таблицю з довільними полями: field_1, field_2і т.д. Це дає більш чистий реляційний дизайн, хоча по- , як і раніше не ідеальні. Чи є це переважним для трохи сфери, багато в чому є питанням думки, оскільки жодне рішення не є ідеальним.

Якщо ви знаєте, що представляють біти під час розробки, то створіть поля для кожного біта і дайте їм значущі імена .

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


2

Я неоднозначний щодо бітових масок. Я вважаю, що більшість їхніх недоброзичливців не розуміють бінарних та шістнадцяткових. Для наочності використовуйте хороші мнемоніки.

Перевага, не згадана вище, - це можливість додавати нове значення бітовим маскам без потенційно багаторазового додавання нового стовпця. Наші дизайнери db (які передували мені) містять їх у таблиці, яка щодня отримує 5 мільйонів нових записів. Додавання нового стовпця для представлення нової поведінки зайняло б багато часу, тоді як визначення нового біта (ми спожили 33 з 64) не потребує перебудови таблиці.

Ні, бітові маски не можна індексувати, але створення 33 індексів було б смішним і сповільнило б вставки до сканування. Пошук у таблиці використовує індекси дати та запису "власників", отже, індекси на цій бітовій масці, якщо можливо, ніколи не використовуються.


Це цікавий випадок. Я припускаю, що ви могли б досягти того ж кошерно і явно, визначивши «запасні» стовпчики на столі, а потім застосувавши їх до необхідності. Потім ви можете принаймні вибірково індексувати ці стовпці, якщо ви вирішите це зробити.
Стів

1

Якщо мета просто заощадити трохи дискового простору, я думаю, це погана ідея:

  • подивіться на вартість GB сьогодні,
  • порівняйте його з витратами часу тих, хто пише звіти та запити, і повинні з'ясувати, що в цій галузі, і як вирішити конкретний біт, порівняння витрат і вигод може закінчитися з неправильної сторони.
  • якщо ви працюєте з базою даних SQL, додаткові операції доступу до бітів, необхідні для багатьох запитів, також можуть забирати більше часу, ніж потрібно

Однак є деякі випадки, які можуть призвести до використання бітових полів:

  • якщо ваші біти являють собою складний набір прапорів, якими ви завжди керуєте разом у цілому,
  • навіть більше, якщо вам потрібно застосувати деякі алгоритми відповідності шаблону до цих наборів,
  • і особливо, якщо ці дані не входять до числа найбільш часто використовуваних критеріїв відбору.
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.