对于可变数量的组合,最好的 table 结构是什么?

What would be the best table structure for variable amount of combination?

我需要一些建议来选择我的 table 结构。

我正在做一个项目,我需要保存由可变数量的其他值组合而成的值。

例如:

A = b,c,d
B = z,r

我正在考虑将组合保存在列内的 json 对象中,但我担心对于大请求来说它可能会很长并且不容易过滤。

也有多个列的解决方案(不需要时包含 null),但这不能很好地表示数据,而且过滤也很困难。

最后我认为最好的是多对多关系,但是连接可能太重了,是吗?

你看到任何其他选择(除了切换到 nosql 之外)吗?

这显示了使用 Junction tables 来避免将数据保存在逗号分隔的列表中,json 或至少在这些区域会出现问题的其他机制:

  • Tables-scans(速度慢,快速索引的 non-use)
  • 维护数据
  • 数据完整性

架构

create table cat
(   -- categories
    id int auto_increment primary key,
    code varchar(20) not null,
    description varchar(255) not null
);

create table subcat
(   -- sub categories
    id int auto_increment primary key,
    code varchar(20) not null,
    description varchar(255) not null
);

create table csJunction
(   -- JUNCTION table for cat / sub categories
    -- Note: you could ditch the id below, and go with composite PK on (catId,subCatId)
    -- but this makes the PK (primary key) thinner when used elsewhere
    id int auto_increment primary key,
    catId int not null,
    subCatId int not null,
    CONSTRAINT fk_csj_cat FOREIGN KEY (catId) REFERENCES cat(id),
    CONSTRAINT fk_csj_subcat FOREIGN KEY (subCatId) REFERENCES subcat(id),
    unique key (catId,subCatId) -- prevents duplicates
);


insert cat(code,description) values('A','descr for A'),('B','descr for B'); -- id's 1,2 respectively

insert subcat(code,description) values('b','descr for b'),('c','descr for c'),('d','descr for d');  -- id's 1,2,3
insert subcat(code,description) values('r','descr for r'),('z','descr for z'); -- id's 4,5

-- Note that due to the thinness of PK's, chosen for performance, the below is by ID
insert csJunction(catId,subCatId) values(1,1),(1,2),(1,3); -- A gets a,b,c
insert csJunction(catId,subCatId) values(2,4),(2,5);    -- B gets r,z

好的错误

以下错误正常且符合预期,数据保持干净

insert csJunction(catId,subCatId) values(2,4); -- duplicates not allowed (Error: 1062)
insert csJunction(catId,subCatId) values(13,4); -- junk data violates FK constraint (Error: 1452)

其他评论

针对您的评论,仅在 mysql 具有最近使用 (MRU) 策略的情况下才缓存数据,不多于或少于内存中缓存的任何数据与物理查找。

事实上 B 目前可能不仅包含 z,r,而且 可能 还包含 cA,并不代表有重复。正如在模式中看到的那样,没有 parent 可以复制它对 child 的包含(或重复),无论如何这将是一个数据问题。

请注意,使用 code 列可以很容易地完成 cat 和 subcat 中的 PK 路线。不幸的是,这会导致索引变宽,甚至会导致结点 table 的复合索引变宽。这将大大减慢操作速度。尽管数据维护在视觉上可能更具吸引力,但我每天都倾向于 performance 而不是 appearance

当时间允许时,我将添加到此答案中以显示 "What categories contain a certain subcategory"、删除等内容