数据库设计之存储多值的问题
2016-03-22 11:48
204 查看
存储多值的问题在设计数据库时是很普遍的问题,看到很多开发人员在上面吃了亏,我觉得有必要拿出来说。
业务场景:一个业务单据,有多个联系人。一个设备维护工作,有多个维护班组。下面来举个例子
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. 多值的问题如何抉择呢?
方案一肯定是不要选的。
方案二适合于对多值列没有分析统计,没有查询。
方案三是我心中理想的方案,虽然它可能会造成一些工作量。
业务场景:一个业务单据,有多个联系人。一个设备维护工作,有多个维护班组。下面来举个例子
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. 多值的问题如何抉择呢?
方案一肯定是不要选的。
方案二适合于对多值列没有分析统计,没有查询。
方案三是我心中理想的方案,虽然它可能会造成一些工作量。
相关文章推荐
- SQL SERVER 2008 同表同列做差
- Mysql事务使用总结
- Oracle中dual表的用途介绍
- [转】[tip] localhost vs. (local) in SQL Server connection strings
- mysqldb
- 初学者 函数和存储过程
- oracle 10g dataguard 搭建
- win7 64位下安装oracle 10g(10.2.1)切身体会,不需要安装oracle客户端,实现navicat和plsql连接数据库
- SQL查询性能分析之(not in)、(and not)、()、(!=)性能比较
- MySQL数据库总结(13)存储过程与函数
- SQL Server数据库被置疑的解决方案
- JDBC连接数据库步奏
- postgresql 正则暗坑
- day9mysql操作
- hadoop hive sql语法解释
- 解决mysql添加任务计划作业时,报‘事件计划已关闭。事件只能在服务器启动并开启事件计划时才能处理。’
- 如何对SQL Server配置动态端口?
- redis 学习笔记(7)-cluster 客户端(jedis)代码示例
- Redis的11种Web应用场景
- 安装mongodb 3.2