请考虑以下表格:
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,当我想取回特定用户可以看到的新闻时,可以使用类似的查询。
2 | 4
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的所有权限。
如果只有几个角色,那么您甚至都不会在 PostgreSQL中* 节省任何 存储 空间。一列使用4个字节,一个8个字节。两者都可能需要对齐填充: *integerbigint
integer
bigint
甲boolean柱使用1个字节。实际上,您可以为一integer列容纳四个或更多的布尔列,为容纳八个或更多的布尔列bigint。
boolean
还应考虑到NULL值仅在NULL位图中使用一位(简化)。
NULL
各个列更易于阅读和 编制索引 。其他人已经对此发表了评论。
您仍然可以利用表达式的索引或部分索引来规避索引问题(“不可扩展”)。通用语句,例如:
数据库无法在这样的查询上使用索引
或者
这些条件是非SARG!
是 不完全正确的 -也许对一些人缺乏RDBMS这些功能。 但是,当您可以完全避免问题时为什么要规避呢?
正如您所澄清的,我们正在谈论6种不同的类型(可能更多)。与各个boolean列一起使用。与之相比,您甚至可以节省空间bigint。在这种情况下,空间需求似乎无关紧要。
如果 这些标志是 互斥的 ,则可以使用 一 列类型enum或一个小的查询表以及一个引用它的外键。(排除了有问题的更新。)
enum