如果你是伴随着结构化数据库成长起来的,请举手!你是否接触过SQL?也许在学校的时候使用过MS Access,而后在工作中涉猎过MySQL。
在数据库管理系统中,SQL作为主角已经有很多年的历史了。如果你是个专业的软件工程师,那么你很有可能已经经历了几十甚至上百个基于SQL的项目,而且很有可能是MySQL,或者MSSQL或者PostgreSQL。
虽然SQL有时会被诟病速度过慢,过于集中化,或者仅仅是老旧,但是不可否认,SQL很稳定,而且在过去的20年中,SQL已经成为了大多数基于web的软件的核心组成部分。不过近些年来,NoSQL数据库管理系统也有着显著的成长趋势。
如果你在创业公司工作,那么这是一个让你接触NoSQL数据库的好机会。创业公司通常没有什么遗留代码需要支持,还会雇佣年轻上进的工程师,鼓励他们探索一切能让它们一下子脱颖而出的会成为下一个大事件的技术。伴随着近些年技术创业公司的兴起,像NoSQL这样的技术一定会取得快速的进步。
另外,众多公有云设施的到来也加快了NoSQL技术的应用:我们可以使用一些简单的点击操作就搭建出一套分布式数据库集群。然后可以使用像NPM和Composer这样的工具一样,迅速的获得一套简单易用的SDK。智能IDE可以通过类型提示的功能帮我们编写一半的代码,而如果我们遇到了问题,我们可以从大量的文档或者有意于推广相关技术的社区使用者那里寻求帮助。
当年的那个最好的服务来自于最大的公司(当然要花钱),很少有人敢使用小公司产品的时代一去不复返了。这也是SQL可以上升到现在这个高度的原因,而NoSQL也正在做着类似的事情。
但是仅仅是因为一个好的旧技术(或者一个时髦的新技术)能被用于一个项目中,就意味着它就应该被用于项目中吗?
选用合适的工具
无论是学习一个新的技术栈多有乐趣,或者在极短的时间内神奇的搭出一个原型有多好玩,作为职业软件工程师,我一向对盲目追随开发趋势持谨慎态度。虽然刚开始的时候每个东西都会打上下一个大事件的标签,但是大多数声称为下一个大事件的项目最终都无声无息的消失了。
在适当的时候做正确的判断是一个微妙的权衡。
SQL支持者能迅速的指出结构化关系型数据的好处。他们会拿出20多年来SQL一直活跃的支撑着软件库的稳定性来作为佐证。
而NoSQL的追随者则喜欢提出当数据不再需要依附于模式时数据将获得的自由度。他们会强调使用NoSQL数据库进行嵌套数据查询时查询能力的提升。
当然,两个阵营都对。但是同时又都是错的。
一些项目(比如,大多数的web应用),拥有非常结构化的数据。有时甚至不需要被搜索到;数字型主键就足够供开发者查询记录。
同样的,有些项目会需要存储庞大的非结构化数据,以供以后进行分析使用。任何处理日志的工具都属于这个类型。这样的项目使用一个SQL数据库是完全没有用的。
审视一个项目的用例是非常重要的,请把你的偏见和对某些技术栈的个人喜好抛在一边。
中间情况怎么办?
以上的应该是基本共识。但是如果你的用例哪边都靠不上怎么办?当你的项目需要将结构化数据存储在一个多层嵌套结构(比如,一个JSON对象)里怎么办?或者当你需要分析、处理非结构化数据,然后再将它存入一个结构化结构中怎么办?亦或者做了这些之后还要在子字段的子字段中查询数据怎么办?
这些才是要变的混乱不堪的地方。
你可以将数据整理为JSON对象,序列化然后存成text类型。近些年的SQL数据库甚至允许你使用JSON字符串进行查询操作。但是你怎么手动的浏览这些数据?你是否能在这个数据的一个子集有所变更的时候,轻松的更新这条数据?
SQL的主旨是将存储的数据标准化,将数据处理为有用的信息,然后把数据分离为一些通过外键联系起来的表。这通常是很有效率的,而且有助于手动浏览--你可以从数据的任一部分开始,根据表之间的关联进行一次数据查询。
但是怎么对一个关键词进行查询呢?你应该做一个包含
查询,但是一旦你得到了成千上万条记录,那计算代价将是巨大的。
所以你会想也许你应该把数据存放在NoSQL数据库中。毕竟,这种事情比较适合由NoSQL数据库来做,对吗?
查询数据也许是很容易的,但是管理数据却是一个更大的任务。同时如果没有良好定义的表和模式,当你必须深入数据库进行手动管理时,数据库就像乱成一锅“文档汤”。你可能需要在每次查询时检索所有的数据,而这样的代价势必是沉重的。除非你限制返回列,但是这是否说明了一个问题,那就是没有一个合适的模式供你使用来搞定这件事?另外那些和其他数据有关联的数据记录怎么办?
所以话说回来,任何一个都不是可行的,但是两个加在一起似乎是个可行的解决方案。
解决方案
选择性的接受这个建议--毕竟每个项目的需求都不一样。
在很多情况下,应用在检索和显示信息上花费的时间要比花在更新信息上的时间多。我们在此不讨论聊天室或者区块链类型的应用,而是标准的网络应用。
首先会有一个稳定的数据来源流,但是并不需要在数据提交后立刻被访问到。通常数据被放在队列中,然后在几秒钟后由微服务来进行处理,这是完全可以被接受的。如果程序特别大,那么这将是程序设计的一个大需求点。
在这种机制下,可是考虑一下两种不同的数据库角色。有一个内部数据库--应用和相关的微服务与之通讯,处理那些用户看不到的工作--和一个外部数据库--直接反馈用户的请求。
内部数据库应该是能被轻松替换的。它会被知晓主键关系的内部服务访问,并且能够处理高结构化数据。外部数据库则需要能应对用户的任何请求;也许是一个简单的关键词搜索,或者是个复杂的带有拼写错误的关键字的布尔和关键字查询。
内部数据库可以是个常规的SQL服务,处理标准化数据,并以能完全描述数据复杂性的形式将数据分离并放入表中。不应该在这上面跑查询, 所以并不需要需要非常重视能以最小的开销进行联合查询。这非常依赖于来自于同一个初始化数据集的用以连接信息的外键。
它也会在每次CUD(create,update,delete)操作时触发一个动作。
这个触发动作会将信息收集到一个独立的文档中,比如一个嵌套的JSON对象。然后将这份文档插入或者更新到外部数据库中;也就是你选择的NoSQL数据库。对于这个目标,我个人在Elasticsearch上有很多的经验。
从用户那里来的请求,无论多么复杂,都能形成一个针对NoSQL数据库的查询,而这个查询是很快的。如果性能不够好,那么只要改变一下文档的结构(或者,比如说使用了Elasticsearch,索引要进行映射)或者重新对数据构建索引,来达到提升性能的目的。
外部数据库完全可以处理读请求。如果你想针对一款无需向下兼容的应用的搜索进行修改,你可以并行的将数据构建索引后放入新的数据库中,然后在结束后进行一次性的无缝切换。
最终的结果是一个近乎实时的、结构化的、易于更新的、查询非常快的、并且在吞吐量增加的时候非常容易水平扩展的NoSQL数据库。