什么时候将标志存储为位掩码而不是使用关联表?

Rya*_*ohn 75 c# sql-server database-design bitmask

我正在开发一个应用程序,其中用户具有使用不同功能的不同权限(例如,读取,创建,下载,打印,批准等).预计权限列表不会经常更改.我有几个如何在数据库中存储这些权限的选项.

选项2在哪些情况下更好?

选项1

使用关联表.

User
----
UserId (PK)
Name
Department
Permission
----
PermissionId (PK)
Name
User_Permission
----
UserId (FK)
PermissionId (FK)

选项2

为每个用户存储位掩码.

User
----
UserId (PK)
Name
Department
Permissions
[Flags]
enum Permissions {
    Read = 1,
    Create = 2,
    Download = 4,
    Print = 8,
    Approve = 16
}
Run Code Online (Sandbox Code Playgroud)

Nev*_*uyt 63

精彩的问题!

首先,让我们做一些关于"更好"的假设.

我假设你不太关心磁盘空间 - 从空间的角度来看,位掩码是有效的,但是如果你使用的是SQL服务器,我不确定这很重要.

我假设你关心速度.使用计算时,位掩码可以非常快 - 但在查询位掩码时将无法使用索引.这并不重要,但如果您想知道哪些用户具有创建访问权限,那么您的查询就是这样的

select * from user where permsission & CREATE = TRUE
Run Code Online (Sandbox Code Playgroud)

(今天没有访问SQL Server,在路上).由于数学运算,该查询将无法使用索引 - 因此,如果您拥有大量用户,这将非常痛苦.

我假设你关心可维护性.从可维护性的角度来看,位掩码不像存储显式权限那样具有底层问题域的表达能力.您几乎肯定必须跨多个组​​件(包括数据库)同步位掩码标志的值.并非不可能,但背后的痛苦.

因此,除非有另一种评估"更好"的方法,否则我会说位掩码路由不如将权限存储在规范化的数据库结构中.我不同意它会"慢,因为你必须加入" - 除非你有一个完全不正常的数据库,你将无法衡量这一点(而没有活跃索引的好处的查询可能会变得明显即使有几千条记录也会变慢).

  • 精彩的回答! (6认同)
  • 由于布尔(或SQL Server案例中的位)列的[基数](http://en.wikipedia.org/wiki/Cardinality_%28SQL_statements%29)非常低,因此这些列上的索引完全没用.因此,规范化的解决方案也不具备可用的优化. (5认同)

Ode*_*ded 12

就个人而言,我会使用关联表.

位掩码字段很难查询和连接.

您始终可以将此映射到C#标志枚举,如果性能变为并且重构数据库.

对过早优化的可读性;)

  • 管理和维护.当在位掩码列中对关键信息进行模糊处理时,维护和管理存储在数据库中的数据会有多难?任何性能提升几乎肯定不会足以产生真正的差异. (6认同)

Ada*_*son 5

存储规范化的权限(即不在位掩码中).虽然它显然不是您的场景的要求(特别是如果权限不会经常更改),它将使查询更容易和更明显.


Ali*_*tad 5

没有明确的答案,所以为你做什么工作.但这是我的抓住:

如果使用选项1

  • 您希望权限增长到许多
  • 如果您可能需要执行权限检查数据库存储过程本身
  • 您不希望数百万用户使表中的记录不会大量增长

如果使用选项2

  • 权限将限制为少数
  • 您期待数百万用户