数据库设计实例-标签的设计
越来越多的博客,社交网支持标签(Tag)的使用。比如QQ用户可以从预定义的标签集中选取任意多的标签,也可以自己直接定义标签。如何给用户提供任意多的标签,同时还支持包括并,交,差等复杂的查询逻辑? 实现任意标签本身不是问题,但是如何在大规模数据情况下,系统查询的效率依然可以接受?
【在南京鼓楼地铁站的墙饰,显示标签云的概念】
Philipp Keller比较了几种数据库数据模式。
1)使用一个表,标签之间用空白符分隔,存储在一个表列里。
ID | 内容 | 标签组 |
1 | 这样 | 标签1 标签2 |
2 | 或者那样 | 标签2 标签3 标签5 |
2)使用2个表,其中存储标签的表有一个外键指向主表。
3)使用3个表来反映标签和被标签主体的M:N的关系。
第三种是ORM中处理M:N关系时使用的标准模式,也是3个方案中唯一符合第三范式(3NF)的方案; 但是Philipp使用MySQL的比较结果发现,在数据量比较大时(超过100万),第三种方案无论在查询还是更新操作的效率都显著地低于前两种方案。
如果数据量大,而真正使用的标签组合数相对低(这是实际用户产生的典型数据分布模式), 可以对系统中实际存在的每个标签组合使用一个唯一的标志符(或哈希值),被标签的数据直接存储标签组合的标志符, 而不是标签本身。
这个方案对实际用户产生的数据,效果非常好。 比如Stackoverflow有50万问题,大约2万标签, 每个问题一般使用了不多于5个标签。但是实际使用的标签组合只有几千个。
Delicious网站的创建者Joshua Schachter认为标签完全不适合RDBMS,推荐使用部分索引(partial indexing). 另外一种选择是完全放弃RDBMS,使用诸如Apache Luence和Hadoop。
模式名称: 避免在数据库层实现业务逻辑
动机/试图解决问题: 很多公司的老系统使用大量的数据库触发器和存储过程技术来实现业务逻辑。 数据库适合CRUD操作,当数据库层承担了过多的业务逻辑,难于维护和影响系统构架的进化,难于横向扩展。
原理: 业务逻辑分散在数据库层和应用层,维护困难 ;数据库对横向扩展的支持不如应用程序服务器, 将业务逻辑放在应用服务层,提高了系统的可扩展性 。
使用:
相关模式:
模式名称: 避免使用复杂的数据模式。
动机/试图解决问题: 避免使用复杂的数据模式,提高查询效率,和横向扩展
原理: RDBMS的规范化遵循了DRY原则,但是造成了复杂的数据依赖关系。不利于数据的分割和横向扩展
使用:
相关模式:
模式名称: 尽可能减少锁使用的范围和时间
动机/试图解决问题: 为避免并发冲突,数据库使用了锁机制。但是锁影响了系统的效率。
原理: 乐观锁机制采取了更加宽松的加锁机制。假设不会发生并发冲突,只在提交操作时检查是否违反数据完整性
使用:
相关模式:
模式名称: 减少不必要的查询结果
动机/试图解决问题: 数据查询结果,往往包含很多不需要的信息,增加了对系统资源的占用。
原理: 对查询结果,需要使用分页和各种排序要求来减少每次返回的数据量。同时, 对于每一个数据结果记录, 写明使用的表列名称, 避免产生不必要的数据,并且在表结构变化时避免出错。
使用:
相关模式:
总结:
RDBMS的使用,往往是不可避免的。数据库往往是系统中最难横向扩展的部分,因此需要将业务逻辑从数据库层分离;同时在建立数据模式时要考虑到横向扩展因素。数据库模式的规范化,避免了数据的不一致性,但是也使得数据难以分割。因此需要适度的去规范化。同时尽可能使用乐观锁来提高系统效率。