Когда лучше хранить флаги как битовую маску, а не использовать ассоциативную таблицу?

Я работаю над приложением, в котором пользователи имеют разные разрешения на использование разных функций (например, «Чтение», «Создание», «Загрузка», «Печать», «Утверждение» и т. д.). Не ожидается, что список разрешений будет часто меняться. У меня есть несколько вариантов хранения этих разрешений в базе данных.

В каких случаях вариант 2 будет лучше?

Вариант 1

Используйте ассоциативную таблицу.

пользователь
----
UserId (PK)
название
отдел
Разрешение
----
PermissionId (PK)
Имя
User_Permission
----
UserId (FK)
PermissionId (FK)

Вариант 2

Сохраните битовую маску для каждого пользователя.

Пользователь
----
UserId (PK)
название
отдел
Права доступа
[Flags]
enum Permissions {
    Read = 1,
    Create = 2,
    Download = 4,
    Print = 8,
    Approve = 16
}
73 голоса | спросил Ryan Kohn 19 AMpTue, 19 Apr 2011 00:04:26 +040004Tuesday 2011, 00:04:26

9 ответов


0

Великолепный вопрос!

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

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

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

select * from user where permsission & CREATE = TRUE

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

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

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

ответил Neville Kuyt 19 AMpTue, 19 Apr 2011 00:15:51 +040015Tuesday 2011, 00:15:51
0

Лично я бы использовал ассоциативную таблицу.

Поле битовой маски очень сложно запрашивать и присоединять.

Вы всегда можете сопоставить это с вашим перечислением флагов C # и, если производительность повысится, и выполнить рефакторинг базы данных.

Читаемость по преждевременной оптимизации;)

ответил Oded 19 AMpTue, 19 Apr 2011 00:06:11 +040006Tuesday 2011, 00:06:11
0

Сохранение разрешенных разрешений (т.е. не в битовой маске). Хотя это, очевидно, не является требованием для вашего сценария (особенно если разрешения не часто меняются), это сделает запрос намного проще и более очевидным.

ответил Adam Robinson 19 AMpTue, 19 Apr 2011 00:06:52 +040006Tuesday 2011, 00:06:52
0

Нет однозначного ответа , поэтому делайте то, что вам подходит . Но вот мой улов:

Используйте опцию 1, если

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

Используйте вариант 2, если

  • Разрешения будут ограничены несколькими
  • Вы ожидаете миллионы пользователей
ответил Aliostad 19 AMpTue, 19 Apr 2011 00:07:54 +040007Tuesday 2011, 00:07:54
0

Единственный раз, когда я могу подумать, когда я буду использовать поле битовой маски для хранения разрешений, это когда вы действительно действительно ограничены в том, сколько физической памяти у вас есть ... как, возможно, на старом мобильном устройстве. По правде говоря, объем памяти, который вы экономите, не стоит того. Даже у миллионов пользователей пространство на жестком диске дешево, и вы можете значительно расширить разрешения и т. Д., Используя подход без битовых масок (это касается сообщения о том, кто имеет какие разрешения и т. Д.)

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

ответил kemiller2002 19 AMpTue, 19 Apr 2011 00:08:25 +040008Tuesday 2011, 00:08:25
0

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

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

ответил Simon Dufour 19 AMpTue, 19 Apr 2011 00:08:49 +040008Tuesday 2011, 00:08:49
0

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

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

ответил Mike M. 19 AMpTue, 19 Apr 2011 00:15:04 +040015Tuesday 2011, 00:15:04
0

Я не рекомендую использовать битовую маску по следующим причинам:

  • Индекс не может быть эффективно использован
  • Запрашивать сложнее
  • На читаемость /обслуживание сильно влияют
  • Обычный разработчик не знает, что такое битовая маска
  • Гибкость уменьшена (верхний предел на количество бит в числе)

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

user_permissions(
   user_id
  ,read     
  ,create   
  ,download 
  ,print    
  ,approve  
  ,primary key(user_id)
);

Добавление столбца является модификацией схемы, но я предполагаю, что добавление привилегии «Очистка» потребует некоторого кода для ее согласования, поэтому привилегии могут быть не такими динамичными, как вы думаете.

Если у вас плохое распределение данных, например, 90% базы пользователей не имеют ни одного разрешения, следующая модель также работает нормально (но разваливается при выполнении больших сканирований (одно 5-стороннее соединение против одно полное сканирование таблицы).

user_permission_read(
   user_id
  ,primary key(user_id)
  ,foreign key(user_id) references user(user_id)
)

user_permission_write(
   user_id
  ,primary key(user_id)
  ,foreign key(user_id) references user(user_id)
)

user_permission_etcetera(
   user_id
  ,primary key(user_id)
  ,foreign key(user_id) references user(user_id)
)
ответил Ronnis 19 AMpTue, 19 Apr 2011 00:42:28 +040042Tuesday 2011, 00:42:28
0

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

ответил smartcaveman 19 AMpTue, 19 Apr 2011 00:06:35 +040006Tuesday 2011, 00:06:35

Похожие вопросы

Популярные теги

security × 330linux × 316macos × 2827 × 268performance × 244command-line × 241sql-server × 235joomla-3.x × 222java × 189c++ × 186windows × 180cisco × 168bash × 158c# × 142gmail × 139arduino-uno × 139javascript × 134ssh × 133seo × 132mysql × 132