这显示了使用连接表来避免将数据保存在逗号分隔的列表、json 或其他机制中,这些机制至少会在这些领域出现问题:
- 表扫描(速度慢,不使用快速索引)
- 数据维护
- 数据完整性
架构
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)
其他cmets
为了响应您的 cmets,数据仅在 mysql 具有最近使用 (MRU) 策略的情况下被缓存,不比任何缓存在内存中的数据与物理查找相比多或少。
B 目前可能不仅包含z,r,而且它可能也包含c 和A 一样,但这并不意味着存在重复。从架构中可以看出,没有父级可以复制其对子级的包含(或重复),这无论如何都是数据问题。
请注意,使用code 列可以轻松地在 cat 和 subcat 中进行 PK。不幸的是,这将导致广泛的索引,甚至更广泛的连接表的复合索引。这将大大减慢运营速度。尽管数据维护在视觉上可能更具吸引力,但我倾向于performance 而不是appearance。
如果时间允许,我将在此答案中添加“哪些类别包含某个子类别”、删除等内容。