随着工作经验的积累,我日益感觉到,对一名程序员来说,拥有良好的数据库设计能力是很重要的,甚至是最重要的。
程序员界有一句著名的话
Talk is cheap, show me the code
把这句话演变一下,就成了
Code is boring, show me the data structure
数据库的种类很多,对于像作者这样的web后端程序员来说,可以把范围缩小到关系型数据库、非关系型数据库与NoSQL数据库。
数据结构为何如此重要
一切代码都是围绕数据结构运行的。
客户端展现的动态数据,都是存储在数据库中,这对程序员来说一定是常识了。拿你正在浏览的这个页面为例,文章的作者、标题、正文、评论、喜欢等等,只要你打开任意两篇文章,两个页面不一样的地方,几乎都是因为在数据库中存储的内容不同。
良好的数据结构可以提升性能,使代码变得简单、清晰。数据结构清晰了,围绕着数据运行的代码自然就清晰了。
数据库设计需考虑的因素
提到数据库设计原则,首先会想到第一、第二、第三范式,这些理论能了解最好,但这不是本文探讨的主题。
面对一个具体的应用场景,设计数据库时应考虑哪些因素?为了能够言之有物,我们拿简书的文章页面来现身说法。
当前可用性
数据结构的设计要能达到应用场景的要求,这是最基本的。举个例子,这篇文章的正文存储在了数据表中的某个字段,该字段的长度被设定为1000字,这显然不能满足应用场景的要求,文章写到这里已经超过了1000字(估计的,我没有数)。
适当超前
超前到什么程度需要根据对应用的预期来定。拿QQ来说,马化腾最初肯定预见不到QQ能有目前的用户量与活跃度,毕竟那是近20年前的事情了。
对于本文设定的应用场景,我们把超前设定为网站的文章数量达到了千万级。这时如果只把文章存在一张数据表里,读写性能必然是会急剧下降的,这必然会导致用户体验变差,用户流失。老板不能容忍,DBA也不能容忍。
合理的解决方案之一是分为两张数据表,一张存储热门文章,另一张存储非热门文章。毕竟热门文章占少数,热门文章的加载速度相对就更快了。还有别的解决方案吗?肯定有,留给您自己思考。
分离易变与不易变部分
对于一篇文章来说,哪些是易变的,哪些是不易变(不变)的?
不易变(不变)
作者
标题
正文(字数)
发布时间
更新时间
易变
阅读次数
评论
喜欢该文章的用户与数量
拆分的好处在于,首先数据结构更清晰了,其次可以提高读写性能,当文章有了新评论,只需更新存放评论的数据表。如果不拆分,需要更新的记录占用的磁盘空间很大,这对磁盘IO速度是个考验。
对于拆分出的部分,可以继续运用这些原则进行设计。
应对可能出现的新需求
互联网应用的迭代周期很短,设计数据结构时应考虑到可能出现的新需求。拿喜欢该文章的用户与数量举例。
为了达到应用的要求,最简单的方式是将这些用户放在一条记录里,存储的字段可以是数组类型。这样设计,喜欢文章的用户信息与用户数量都能轻易获取,读写性能也很好。
某天,产品经理找到了你:“商量个新需求呗”,在文章下方加个模块,就叫“喜欢该文章的人还喜欢了”。你就懵逼了,没法破,除非重新设计数据结构,然后就带来了迁移数据一系列事情。其实这个需求挺合理的,说得高大上一点,这叫“精准推荐”。
很明显,将用户放在数组里只能支持“查询喜欢某文章的用户”,不支持“查询某用户喜欢的文章”。
适当的冗余
或许你已经注意到了,文章的标题下面有这篇文章的字数。计算文章的字数,有两个时机:
保存文章时
读取文章时
后者的优势在于数据表中少了一个字段,而且这个字段不是必需的。哪个时机更好?个人觉得前者更好,理由如下:
计算长篇文章的字数是比较耗时的,应尽量减少计算次数
总体来看,文章的保存次数远小于读取次数
如果能够提高应用的性能,适当的冗余是必要的。
结尾
本文总结了设计数据库时需遵守的几个原则
可用性
适当超前
应对新需求
分离易变与不易变部分
适当冗余
因为自知还未达到数据库专家的水准,写出的内容肯定有不准确的地方,欢迎批评指正。
写这篇文章的想法酝酿很久了,但一直没时间动笔。适逢中秋佳节,上海下着大雨,不便出门行走,便安坐在电脑前敲下了这千八百字,前后花了两个多小时。如果喜欢就点赞,能指出不足或提出意见就更好了。
网友评论