关系型数据库的演变以及非关系型数据库
文章目录
数据库分类
而在当今的互联网中,最常见的数据库模型主要是两种,即关系型数据库和非关系型数据库。
什么是关系型数据库
关系型数据库
是建立在关系模型基础上的数据库,就是说它需要预定义固定模式的表来存储所有数据
关系型数据库用了选择、投影、连接、并、交、差、除、增删查改等数学方法来实现对数据的存储和查询。可以用SQL语句方便的在一个表或多个表之间做非常复杂的数据查询。安全性高。
MySQL数据库的模式的发展
mysql的单机时代
这个时候网站的访问量不是很大,而且也是静态网页,动态交互类型的网站不多,产生的数据不是很大,这个时候mysql单机就足够了,但是当数据量增大,就存在瓶颈了。
分析一下这个时候的存储瓶颈
- 数据量的增大,大到一个机器放不下时
- 数据的索引(B+ Tree)一个机器的内存放不下时
- 访问量(读写混合)一个实例不能承受
这个时候为了解决访问量问题
就在App和Mysql数据库中间加了一个DAL(数据库访问层)
数据库访问层的主要职责是:读取数据和传递数据。
Memcached(缓存)+ MySQL + 垂直拆分
当访问量继续上升,几乎大部分使用MySQL架构的网站在数据库上都开始出现了性能问题,无法满足快速查询与插入数据的需求,这个时候程序员就开始大量使用缓存技术(在数据库访问层加缓存)来缓解数据库的压力,并且对数据库进行垂直拆分(主要是针对写压力)。
什么是垂直拆分?
垂直拆分它是数据库拆分的一种,数据库拆分分为 垂直拆分,水平拆分,基于hash拆分,基于路由拆分
-
按功能划分(垂直划分)
一个数据库由很多表的构成,每个表对应着不同的业务,垂直切分是指按照业务将表进行分类,拆分到不同的数据库上面,这样也就将数据或者说压力分担到不同的库上面
比如淘宝中期开始的数据库端按照业务垂直拆分:按照业务交易数据库、用户数据库、商品数据库、店铺数据库等进行拆分。
优点:
-
拆分后业务清晰,拆分规则明确。
-
系统之间整合或扩展容易。
比如说:我们的系统现在要增加新的业务(功能),我们直接添加新的数据库,创建相应的表就可以了。
-
数据维护简单
缺点:
-
部分业务表无法join(比如我们的CRM项目客户模块要用用户表,用户模块也要用户表,但是用户表根据垂直划分只能划到一个数据库这部分的表无法join),只能通过接口方式解决,提高了系统复杂度。
-
受每种业务不同的限制存在单库性能瓶颈(当伴随着某一个表的数据量越来越大,以至于不能承受的时候,就需要对它进行进一步的切分),不易数据扩展跟性能提高。本身数据库就快满了就不能再加数据了,这样就限制了数据的扩展。
-
事务处理起来也比较复杂。
-
-
按表中某一字段值id范围划分(水平划分)
它是用来解决垂直拆分后遇到单库瓶颈的问题的,相对于垂直拆分的区别是:垂直拆分是把不同的表拆到不同的数据库中,而水平拆分是把同一个表拆到不同的数据库中。它可以按照某一个规则来拆分,这个规则我们可以定,我们有多种拆分选择。比如说:
一种选择是根据ID的范围来做切分,譬如ID 为 1-10000的放到A上,ID 为10000~20000的放到B。这样的扩展就是可预见的。另一种是根据某一字段值来划分,譬如根据用户名的首字母,如果是A-D,就属于A,E-H就属于B。这样做也存在不均衡性,当某个范围超出了单点所能承受的范围就需要继续切分。还有按日期切分等等。
总结起来:按照某个字段的某种规则来对表的行进行划分,然后分散到多个库之中,每个库的表中都包含一部分数据。
优点:单表大小可控,天然水平扩展
就拿那个根据ID划分来说,我们就规定好了一张表就存10000条数据
缺点:无法解决集中写入瓶颈的问题
添加还好说,就比如修改,恰好修改的数据没在一个数据库
-
基于hash的划分
-
基于路由表的划分
数据拆分前其实是要首先做准备工作的,然后才是开始数据拆分,我先讲拆分前需要做的事情:
- 第一步:采用分布式缓存redis等降低对数据库的读操作。
- 第二步:如果缓存使用过后,数据库访问量还是非常大,可以考虑数据库读、写分离原则。这个读写分离就是下面要讲的
- 第三步:当我们使用读写分离、缓存后,数据库的压力还是很大的时候,这就需要使用到数据库拆分了。
数据拆分也是先垂直拆分再水平拆分
原则不讲
数据库拆分原则:就是指通过某种特定的条件,按照某个维度,将我们存放在同一个数据库中的数据分散存放到多个数据库(主机)上面以达到分散单库(主机)负载的效果。
MySQL主从读写分离
由于数据库的写入压力增加,缓存只能缓解数据库的读取压力,当前的读写集中在一个是数据库上让数据库不堪重负当写入操作导致数据库崩溃它会影响读取操作,也会导致数据的一些丢失,然后就开始用主从复制技术来实现读写分离,提高读写性能和读库的可扩展性,其实和我们学redis的主从读写分离差不多
在多个服务器上部署mysql,将其中一台当作主数据库,而其他当作从数据库,实现主从同步。其中主数据库负责主动写的操作,而从数据库则只负责主动读的操作(slave从数据库仍然会被动的进行写操作,为了保持数据一致性),这样就可以很大程度上的避免数据丢失的问题,同时也可减少数据库的连接,减轻主数据库的负载。
分表分库+水平拆分+Myql集群
在数据量更大的时候,在之前高速缓存,MySQL主从复制,读写分离的基础上Mysql主库还是出现了写压力,开始出现瓶颈,而且由于MyISAM使用表锁,在高并发下会出现严重的锁问题,大量的高并发MySQL应用开始使用InnoDB引擎代替MyISAM。
什么是写压力
在插入数据的时候,会对表进行加锁,分为表锁定和行锁定。
无论是哪种锁定方式,都意味着前面一条数据在操作表或者行的时候,后面的请求都在排队,当访问量增加的时候,都会影响数据库的效率。
这种模式 分表分库+水平拆分+mysql集群
性能不能很好满足互联网的需求,只是在高可靠性上提供了非常大的保证。
回归正题怎么解决写压力和数据增长的扩展问题?分表分库就出现了,
讲分库分表之前先聊一下数据库的存储演变
- 一开始是单库单表
- 然后就是单库多表就像我们做到项目就是一个数据库多张表
- 多库多表 这就因为一台数据库存储空间有限,单台数据库服务器无法支撑,这个时候可以再对数据库进行水平划分(用来解决单机瓶颈的)。
大概什么情况考虑分库分表?
- 当读压力很大的时候,可以考虑添加Slave机器的分式解决,但是当Slave机器达到一定的数量就得考虑分库了。
- 当写压力很大的时候,就必须得进行分库操作
MySql数据库分库分表的规则
设计表的时候需要确定此表按照什么样的规则进行分库分表。例如,当有新用户时,程序得确定将此用户信息添加到哪个表中;同理,当登录的时候我们得通过用户的账号找到数据库中对应的记录,所有的这些都需要按照某一规则进行。
路由
通过分库分表规则查找到对应的表和库的过程。如分库分表的规则是user_id mod 4的方式,当用户新注册了一个账号,账号id的123,我们可以通过id mod 4的方式确定此账号应该保存到User_0003表中。当用户123登录的时候,我们通过123 mod 4后确定记录在User_0003中。
但是分库分表想法上是好的,也带来了一些新的问题
-
分库分表维度的问题
什么意思呢?举个例子
假如用户购买了商品,需要将交易记录保存起来,如果按照用户的维度分表,则每个用户的交易记录都保存在同一表中,所以很快很方便的查找到某用户的购买情况,但是某商品被购买的情况则很有可能分布在多张表中,查找起来比较麻烦。反之,按照商品维度分表,每个商品的交易记录都保存在同一表中可以很方便的查找到此商品的购买情况,但要查找到构买人的交易记录比较麻烦。
所以常见的解决方式有:
a.通过扫表的方式解决,此方法基本不可能,效率太低了。
b.记录两份数据,一份按照用户纬度分表,一份按照商品维度分表。
c.通过搜索引擎解决,但如果实时性要求很高,又得关系到实时搜索。 -
联合查询的问题
联合查询基本不可能,因为关联的表有可能不在同一数据库中。
-
我们需要避免跨库事务带来
避免在一个事务中修改db0中的表的时候同时修改db1中的表,一个是操作起来更复杂,效率也会有一定影响。
- 尽量把同一组数据放到同一数据库服务器上
把同一组数据放到一个数据库,不要放到多个数据库,这样的话,数据库中的数据依赖另一数据库中的数据。不然的话其中有一个数据库挂掉了,就会影响所有的功能实现,
MySQL的扩展性瓶颈
MySQL数据库也经常存储一些大文本的字段,导致数据库表非常的大,在做数据库恢复的时候就导致非常的慢,不容易快速恢复数据库,比如1000万4KB大小的文本就接近40GB的大小,如果能把这些数据从MySQL省去,MySQL将变的非常的小,关系数据库很强大,但是它并不能很好的应付所有的应用场景,MySQL的扩展性差(需要复杂的技术来实现),
大数据下IO压力大,表结构更改困难,正是当前使用MySQL的开发人员面临的问题。
为什么用NoSQL?
今天我们可以通过第三方平台(如:Google,FaceBook等)可以很容易的访问和抓取数据。用户的个
人信息,社交网络,地理位置,用户生成的数据和用户操作日志已经成倍的增加、
因为数量大,而且关系型数据库表结构更改困难等等,我们如果要对这些用户数据进行挖掘,那关系型数据库已经不适合这些应用了,而NoSQL数据库的发展却能很好的处理这些大的数据!
非关系型数据库
简称NOSQL,是基于键值对的对应关系,数据存储不需要固定的模式,无需多余操作就可以横向扩展。并且不需要经过SQL层的解析,所以性能非常高。但是不适合用在多表联合查询和一些较复杂的查询中。NoSQL用于超大规模数据的存储
四大家族
- 键值存储型
- 查询速度快,主要用于内容缓存,配置信息等,比如我们学过的redis
- 文档存储型
- 数据结构要求不严格,表结构可变,不需要像关系型数据库一样需要预先定义表结构。比如我们学过的MongoDB,当我们添加的数据需要添加之前没有的字段时,可以直接添加,不需要像关系型数据一样还要先改表结构,而且修改表结构还可能和原来的数据冲突,所以对于像快递的物流订单这样,因为它随着物流运输的过程,订单表需要不断的更新,物流表需要不断的添加新的记录,这样的功能用MongoDB来实现就比较方便
- 列存储型
- 列存储查找速度快,可扩展性强,更容易进行分布式扩展,它适用于分布式的文件系统,应对分布式存储的海量数据。比如:HBase
- 图形存储型
- 它是将数据以图的方式储存,对于社交网络,推荐系统等。专注于构建关系图谱。的用图形存储数据库比较好,比如:Neo4j
但是关系型数据库和非关系型数据库并不是说代替的关系,是互补的关系,我们也常常看到关系型数据库和非关系型数据看一起使用的情况