视频1 视频21 视频41 视频61 视频文章1 视频文章21 视频文章41 视频文章61 推荐1 推荐3 推荐5 推荐7 推荐9 推荐11 推荐13 推荐15 推荐17 推荐19 推荐21 推荐23 推荐25 推荐27 推荐29 推荐31 推荐33 推荐35 推荐37 推荐39 推荐41 推荐43 推荐45 推荐47 推荐49 关键词1 关键词101 关键词201 关键词301 关键词401 关键词501 关键词601 关键词701 关键词801 关键词901 关键词1001 关键词1101 关键词1201 关键词1301 关键词1401 关键词1501 关键词1601 关键词1701 关键词1801 关键词1901 视频扩展1 视频扩展6 视频扩展11 视频扩展16 文章1 文章201 文章401 文章601 文章801 文章1001 资讯1 资讯501 资讯1001 资讯1501 标签1 标签501 标签1001 关键词1 关键词501 关键词1001 关键词1501 专题2001
数据库设计之存储多值的问题
2020-11-09 14:45:41 责编:小采
文档


存储多值的问题在设计数据库时是很普遍的问题,看到很多开发人员在上面吃了亏,我觉得有必要拿出来说。 业务场景:一个业务单据,有多个联系人。一个设备维护工作,有多个维护班组。下面来举个例子 createtable BILL ( bill_id numberprimarykey, bill_name

存储多值的问题在设计数据库时是很普遍的问题,看到很多开发人员在上面吃了亏,我觉得有必要拿出来说。

业务场景:一个业务单据,有多个联系人。一个设备维护工作,有多个维护班组。下面来举个例子

createtable BILL

(

bill_id numberprimarykey,

bill_name varchar2(20),

bill_contentvarchar2(200),

contact_idnumber--来至于user表的user_id

);

1. 在起初的设计中,联系人只有一个,后来需求有变化了,联系人又多个。有几种方案:

方案一:在加几个字段,contact_id1,contact_id2,contact_id3...。

方案二:吧contact_id的number类型改为varchar2,多值一起存储,值与值之间用分割符隔开(如逗号)。

方案三:再加一张表bill_contact

createtable bill_contact

(

bill_id number,

contact_idnumber

);

altertable BILL_CONTACT

addconstraint pk_bill_contactprimarykey (BILL_ID,CONTACT_ID);

2. 对比几个方案

方案一显然不合适,不知道建几个字段合适,就算知道最多有几个联系人,查询起来也很麻烦。查询单中包含联系人100和101的记录,

select *from bill_contact

where (contact_id =100and contact_id1 =101)

or (contact_id =101and contact_id1 =100);

查询单中包含联系人100的记录,

select *from bill_contact

where (contact_id =100or contact_id1 =101 or….);

方案二的优点在于方便,开发人员只需要改动少量的代码,普遍被开发人员采纳。a. 但好景不长,分析、统计功能非常难做,如需要列出在某一段时间内某一位联系人的所有单据;统计出每张单据联系人的数目等。

b. 查询也会变得不高效,类型不一致导致隐式转换,索引失效。

c. 修改起来复杂,需要额外在代码中写一段逻辑处理。

d. 有的系统主键用的是32位UUID,如果联系人又10位,那这个字段长度得是500,有点恐怖。

select *from bill_contact

where contact_idlike'100,%'

or contact_id like'%,100'

or contact_id like'%,100,%';

早前针对这种问题我专门写过优化的方案,数据库设计中单个字段多值的处理

方案三恰好是弥补了方案二的众多确定,开发人员总是担心表关联的性能太差,其实是多余的,因为此时能走到索引。还有一个好处就是可以对联系人的信息进行扩展,如是第一联系人,还是第二联系人,这是方案二无法实现的。改造对于开发人员来说工作量比方案二要大。

select *from bill_contact a, bill_contact b

where a.bill_id = b.bill_id

and b.contact_idin (100,101);

3. 多值的问题如何抉择呢?

方案一肯定是不要选的。

方案二适合于对多值列没有分析统计,没有查询。

方案三是我心中理想的方案,虽然它可能会造成一些工作量。

下载本文
显示全文
专题