随着工作经验的积累,我日益感觉到,对一名程序员来说,拥有良好的数据库设计能力是很重要的,甚至是最重要的。
程序员界有一句著名的话
Talk is cheap, show me the code
把这句话演变一下,就成了
Code is boring, show me the data structure
面对同样的数据结构,一百个程序员会写出一百种风格的代码。看别人写的代码,往往是很boring的。
数据结构为何如此重要
代码是围绕数据结构运行的。
客户端展现的动态数据,都是存储在数据库中,这对程序员来说一定是常识了。
为了便于阐述,我们拿简书的文章页面作为样板。
文章的作者、标题、正文、评论、喜欢等等,只要你打开任意两篇文章,两个页面不一样的地方,几乎都是因为在数据库中存储的内容不同。
良好的数据结构可以提升性能,使代码变得简单、清晰。数据结构清晰了,围绕着数据运行的代码自然就清晰了。
数据库设计需考虑的因素
提到数据库设计原则,首先会想到第一、第二、第三范式,这些理论能了解最好,本文不再赘述了。
从实践的角度面对一个具体的应用场景,设计数据库时应遵循哪些原则?
满足当前需求
数据结构的设计要能达到应用场景的要求,这是最基本的。举个例子,文章的正文存储在了数据表中的某个字段,该字段的长度被设定为10000字,在文章字数没有被限制在10000字以内的前提下,这显然不能满足应用场景的当前需求。需要考虑,什么样的字段类型才能存储大规模的文本数据?
分离主体与附属
文章页面中的元素,哪些是主体部分,哪些是附属部分?
一篇文章可以没有评论,评论的有无、多少不影响文章本身的完整性,评论可以被添加、删除。由此可见,文章的评论属于附属部分。阅读次数、喜欢该文章的用户与数量同样如此。
主体
- 作者
- 标题
- 正文(字数)
- 发布时间
- 更新时间
附属
- 阅读次数
- 评论
- 喜欢该文章的用户与数量
拆分的好处在于,首先数据结构更清晰了,其次可以提高读写性能。当文章有了新评论,只需更新存放评论的表。如果不拆分,需要更新的记录占用的磁盘空间很大,这对磁盘IO速度是个考验。
适当的冗余
或许你已经注意到了,文章的标题下面有这篇文章的字数。计算文章的字数,有两个时机:
- 保存文章时
- 读取文章时
后者的优势在于数据表中少了一个字段,而且这个字段不是必需的。哪个时机更好?个人觉得前者更好,理由如下
- 计算长篇文章的字数是比较耗时的,应尽量减少计算次数
- 总体来看,文章的保存次数远小于读取次数
如果能够提高应用的性能,适当的冗余是必要的。
页面的头部有文章作者的昵称,这适合作为冗余字段存储在文章主体数据中吗?用户可以随时更改自己的昵称,如果将昵称作为冗余字段,需要额外的工作以保持数据一致性,从这一点看,用户昵称不适合作为冗余字段。
选择作为冗余的字段应不需要额外的工作来保持数据一致性。
应对可能出现的新需求
如何存储喜欢文章的用户信息才能做智能推荐?一个好的数据结构应该能应对可能出现的新需求。
为了达到应用的要求,最简单的方式是将这些用户放在一条记录里,存储的字段可以是数组类型。这样设计,喜欢文章的用户信息与用户数量都能轻易获取,读写性能也很好。但对于“喜欢该文章的人还喜欢了”此类的智能推荐,这样的设计明显是难以应对的。将用户放在数组里支持“查询喜欢某文章的用户”,对“查询某用户喜欢的文章”的支持就很差或者根本做不到了,这是一种单向查询的数据结构。
应对大数据量
随着用户量不断增加,网站业务数据越来越多,文章数量也达到了百万级。这时如果只把文章存在一张数据表里,读写性能必然是会急剧下降的,这可能会导致用户体验变差,用户流失。老板不能容忍,DBA也不能容忍。
合理的解决方案之一是分为两张数据表,一张存储热门文章,另一张存储非热门文章。热门文章的占比很少,相应的加载速度就会好于非热门文章。
结尾
本文总结了设计数据库时需遵守的几个原则
- 满足当前需求
- 分离主体与附属
- 适当的冗余
- 应对可能出现的新需求
- 应对大数据量
认识到数据结构的重要性,才能设计出好的数据结构。