roc*_*oco 19 postgresql database-design
我有一堆需要与用户帐户关联的布尔值。它们需要在真假之间切换,尽管不是特别频繁——它们被阅读的次数将比写入的次数更多。大多数情况下,它们只会从 False 设置为 True 一次,但情况并非总是如此。
现在我正在考虑将列附加到用户表中:
| 用户身份 | other_user_cols | did_a | did_b | did_c |
|---|---|---|---|---|
| 1 | ... | 错误的 | 真的 | 错误的 |
| 2 | ... | 错误的 | 错误的 | 错误的 |
| 3 | ... | 真的 | 错误的 | 错误的 |
问题是,有很多这样的布尔列。
假设您需要添加 100 列。这真的仍然是最好的方法吗?
认为:
我觉得这一定是一个非常常见的模式,但是这种将更多布尔列塞入我的表的方式似乎相当混乱。有没有更典型的方法来做它更干净一点?或者这实际上是最好的方法?
为此,我正在使用 Postgres。
以下是我考虑过的一些替代方案:
| 用户身份 | 标志名称 | 价值 |
|---|---|---|
| 1 | did_a | 错误的 |
| 1 | did_b | 错误的 |
| 3 | did_a | 真的 |
作为替代方案,这对我来说似乎是最合理的,但不确定是否真的值得麻烦,或者是否有更好的方法。
小智 28
我看不到任何用例,其中有 100 个与用户直接相关的布尔变量,因此属于用户表。我的猜测是这些布尔值用于培训、认证或类似的。我将在我的其余答案中假设这一点。
单独的表“user_training”是执行此操作的方法。在此表中,您有“user_id”和“training_id”。您不需要布尔值,如果该行在数据库中,则培训已完成。
可能需要不时添加新的
使用这种架构不需要向数据库添加新列。只有一个新行。或者,如果数据库包含用于训练的表,则将训练添加到该表中,并且“training_id”指的是该表。
布尔值没有以自然可以更好地组织的方式在逻辑上相关
如果布尔值有多个上下文,则可以使用多个表。想想“user_training”、“user_certification”、“user_something”、“user_whatever”等。这需要更长的时间来完成,但不会花太多时间。你未来的自己会为此感谢你,因为在需要时修复不相关的数据会很麻烦。
如果上下文真的是分开的,你可以只用一张表来完成,比如“user_action”或“user_properties”。
请注意,您还需要决定一些事情。您是否应该有一个包含有关培训名称信息的“培训”表?如果是这样,您可以添加额外的培训,而无需更改应用程序或数据库结构。您想将某些“training_id”设为默认值吗?如果是这样,您如何知道每个培训的默认设置是什么?默认值应该在“训练”表中吗?
Lau*_*lbe 14
我推荐使用varbit,主要是因为它节省空间。当然,存储空间很便宜,但你必须在 RAM 中缓存,这并不便宜,而且操作较小的行性能要好得多。
它也很容易操作:
CREATE TABLE mytable (id bigint PRIMARY KEY, flags varbit);
INSERT INTO mytable VALUES (1, b'11010001000110100');
Run Code Online (Sandbox Code Playgroud)
获取第十个标志的值:
SELECT get_bit(flags, 9) FROM mytable WHERE id = 1;
get_bit
?????????
0
(1 row)
Run Code Online (Sandbox Code Playgroud)
要更改第十个标志:
UPDATE mytable SET flags = set_bit(flags, 9, 1) WHERE id = 1;
SELECT * FROM mytable WHERE id = 1;
id ? flags
????????????????????????
1 ? 11010001010110100
(1 row)
Run Code Online (Sandbox Code Playgroud)
在最后添加一个新位:
UPDATE mytable SET flags = flags || b'1' WHERE id = 1;
Run Code Online (Sandbox Code Playgroud)
小智 3
有四种模式:column、composite_type、array、json
数组是我最喜欢的模式,因为,
这是列、复合和数组的示例;
drop table if exists t_manycolumns ;
drop table if exists t_composite ;
drop table if exists t_arry ;
drop type if exists type_bits;
create table t_manycolumns
(id int,
is_1 boolean,
is_2 boolean,
is_3 boolean,
is_4 boolean,
is_5 boolean,
is_6 boolean,
is_7 boolean,
is_8 boolean
);
create type type_bits as (
is_1 boolean,
is_2 boolean,
is_3 boolean,
is_4 boolean,
is_5 boolean,
is_6 boolean,
is_7 boolean,
is_8 boolean);
create table t_composite(
id int,
is_bits type_bits
);
create table t_arry(
id int,
is_bits boolean[]
);
-- column
insert into t_manycolumns (id, is_1, is_2, is_3, is_4, is_5, is_6, is_7, is_8)
select id, false, false, false, false, false, false, false, false from generate_series(1,100) id;
--composite type
insert into t_composite (id,is_bits)
select id, '(false, false, false, false, false, false, false, false)' from generate_series(1,100) id;
--array type
insert into t_arry (id,is_bits)
select id, array[false, false, false, false, false, false, false, false] from generate_series(1,100) id;
-- demo show search bit true in array
update t_arry
set is_bits[1]=true, is_bits[4]=true
where id in (1,3);
select id, is_bits
from t_arry
where is_bits[1]=true and is_bits[4] =true
order by id
Run Code Online (Sandbox Code Playgroud)
两件重要的事情是:
希望你喜欢。