日期:2014-05-16  浏览次数:20440 次

有个多选匹配的数据库和程序设计问题
现在有这样一个需求,mysql数据库,比如说数据库中有科目表
tb_subject
id varcher(32)
name varcher(20)

教师表
tb_teacher
id varcher(32)
name varchar(20)
现在想在保存教师所带学科(可以带多个学科);

目前有以下3个方案:
1、教师表增加subject_ids 字段,用逗号分隔保存tb_subject表的id,查询时用findinset()函数查找。
2、建立教师、学科关联表
tb_teacher_subject
teacher_id varchar(32)
subject_id varcher(32)
3、教师表增加整型字段subjectsLong int
对tb_subject表中数据按照创建时间排序,为每个记录指定一个不变的序号,从0开始,记录只能新增,不能做物理删除,为的是保证之前的序列号不变。

选择多学科时,获取所选学科的序号列表,传入以下方法,计算出一个Long值,保存到subjectsLong字段
	public static Long StringToLong(List<Integer> bitNumber) {
		Long tl = 0l;
		for (int ti : bitNumber) {
			tl = tl ^ ( 1l << (64 - ti - 1));
		}
		return tl;
	}

查询时用bitand()函数匹配查找。


三个方法所存在的不足:
1、查询效率低下
2、需要多关联一个中间表
3、tb_subject表的总记录数不能超过64个,否则会出现重复值

另外:第三种方案有一个有点,就是在包含查询时,速度很快切很方便。
比如查询条件是语文、数学、英语,我想查询结果列出所有包含这三个科目中任意一个的数据,用方案三就非常方便。但目前实现方法受限于64个科目,希望能有改进方案。


请问大家实现类似需求时,有什么好的方案。
1 楼 LucasLee 2011-03-31  
我看第二种方案是比较标准的,符合数据库设计范式的。
至于关联中间表的问题,我的经验是性能可以接受,至于你的情况是否一样,你也需要用具体的数据测试一下,如果不行,也要针对哪种查询性能不好具体的优化。
2 楼 hubeen 2011-04-01  
推荐方案二,数据库教材上的标准方案,适应绝大多数情况情况。
为关联表增加pk(teacher_id,subject_id)性能不会有太大问题,除非数据量达到1000w级别以上。
查询的时候关联一下关系表稍显麻烦,但是怎么也比你bitmap简单吧。