一尘不染

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

sql

请考虑以下表格:

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是位标志,用于指定可以读取新闻项目的角色的某种组合。因此,如果我插入受限制且机密的新闻可以读取,则将read_roles的值设置为2 | 46,当我想取回特定用户可以看到的新闻时,可以使用类似的查询。

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。

更新
我有点关于数据库不使用索引进行位操作,这将需要全表扫描,这会降低性能。因此,我更新了问题以更紧密地反映我的情况,数据库中的每一行都属于特定公司,因此所有查询都将具有WHERE子句,该子句包括company_fk并在其上具有索引。

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

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


阅读 153

收藏
2021-03-17

共1个答案

一尘不染

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

boolean柱使用1个字节。实际上,您可以为一integer列容纳四个或更多的布尔列,为容纳八个或更多的布尔列bigint

还应考虑到NULL值仅在NULL位图中使用一位(简化)。

各个列更易于阅读和 编制索引 。其他人已经对此发表了评论。

您仍然可以利用表达式的索引部分索引来规避索引问题(“不可扩展”)。通用语句,例如:

数据库无法在这样的查询上使用索引

或者

这些条件是非SARG!

不完全正确的 -也许对一些人缺乏RDBMS这些功能。
但是,当您可以完全避免问题时为什么要规避呢?

正如您所澄清的,我们正在谈论6种不同的类型(可能更多)。与各个boolean列一起使用。与之相比,您甚至可以节省空间bigint。在这种情况下,空间需求似乎无关紧要。


如果 这些标志是 互斥的 ,则可以使用
列类型enum或一个小的查询表以及一个引用它的外键。(排除了有问题的更新。)

2021-03-17