sql - 数据库列中的位标志有什么缺点吗?

标签 sql sql-server oracle postgresql database-design

考虑下表:

CREATE TABLE user_roles(
    pkey         SERIAL PRIMARY KEY,
    bit_id       BIGINT NOT NULL,
    name         VARCHAR(256) NOT NULL,
);

INSERT INTO user_roles (bit_id,name) VALUES (1,'public');
INSERT INTO user_roles (bit_id,name) VALUES (2,'restricted');
INSERT INTO user_roles (bit_id,name) VALUES (4,'confidential');
INSERT INTO user_roles (bit_id,name) VALUES (8,'secret');

CREATE TABLE news(
    pkey          SERIAL PRIMARY KEY,
    title         VARCHAR(256),
    company_fk    INTEGER REFERENCES compaines(pkey), -- updated since asking the question
    body          VARCHAR(512),
    read_roles    BIGINT -- bit flag 
);

read_roles 是一个位标志,指定可以读取新闻项的一些角色组合。因此,如果我要插入一个可以由受限和 secret 阅读的新闻项目,我会将 read_roles 的值设置为 2 | 4 或 6,当我想取回特定用户可以看到的新闻帖子时,我可以使用类似的查询。

select * from news WHERE company_fk=2 AND (read_roles | 2 != 0) OR  (read_roles | 4 != 0) ; 
select * from news WHERE company_fk=2 AND read_roles = 6; 

一般来说,在数据库列中使用位标志有什么缺点?我假设这个问题的答案可能是特定于数据库的,所以我有兴趣了解特定数据库的缺点。

我正在为我的应用程序使用 Postgres 9.1。

更新 我了解到数据库不使用索引进行位操作,这需要全表扫描,这会降低性能。因此,我更新了问题以更准确地反射(reflect)我的情况,数据库中的每一行都属于一个特定的公司,因此所有查询都将包含一个包含 company_fk 的 WHERE 子句,该子句上将有一个索引。

更新 我现在只有 6 个角色,将来可能会更多。

UPDATE 角色不是互斥的,它们相互继承,例如,restricted 继承分配给 public 的所有权限。

最佳答案

如果您只有少数几个角色,您甚至不会在 PostgreSQL 中保存任何存储 空间。一个integer列使用 4 个字节,一个 bigint 8 个字节。两者都可能需要对齐填充:

A boolean列使用 1 个字节。实际上,您可以为一个 integer 列放置四个或更多 bool 列,为 bigint 放置八个或更多列。

还要考虑到 NULL 值仅在 simplified 中使用一位 ( NULL bitmap ) .

单独的列更易于阅读和索引。其他人已经对此发表了评论。

您仍然可以使用 indexes on expressionspartial indexes规避索引问题(“不可搜索”)。概括性陈述如:

database cannot use indexes on a query like this

These conditions are non-SARGable!

不完全正确 - 也许对于其他缺少这些功能的 RDBMS。
但是,既然可以完全避免问题,为什么还要规避呢?

正如您所阐明的,我们正在谈论 6 种不同的类型(可能更多)。使用单独的 boolean 列。与一个 bigint 相比,您甚至可能会节省空间。在这种情况下,空间要求似乎并不重要。


如果这些标志互斥,您可以使用一个 enum 类型的列或者一个小的查找表和一个引用它的外键。 (排除问题更新。)

关于sql - 数据库列中的位标志有什么缺点吗?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/12270461/

相关文章:

sql - PostgreSQL 条件 where 子句

安卓 SQLite : Update Statement

c# - SQLDataAdapter 不返回最后一行数据

sql - 比较 SQL Server 中日期和日期时间的相等性

sql - SQL 中 C 风格的最小/最大?

sql - 删除ORACLE 10g中重复的并发字符

sql - 使 Oracle 排序不区分大小写?

sql - 在 WordPress 表中查找所有图像

sql-server - 如何检查表是否存在于模型中但不存在于数据库中

java - 从 SQL/HQL Java 解析表名和列名