当前位置:网站首页>关系型数据库VS非关系型数据库

关系型数据库VS非关系型数据库

2022-01-15 01:48:17 呼叫冰河谷

Nosql与Sql的区别:

  • 关系型数据库遵循ACID规则,而非关系型没有
  • 关系型数据库针对结构化数据,而非关系型数据库针对非结构/半结构化化数据

ACID规则:

  • A (Atomicity) 原子性:原子性很容易理解,也就是说事务里的所有操作要么全部做完,要么都不做,事务成功的条件是事务里的所有操作都成功,只要有一个操作失败,整个事务就失败,需要回滚。比如银行转账,从A账户转100元至B账户,分为两个步骤:1)从A账户取100元;2)存入100元至B账户。这两步要么一起完成,要么一起不完成,如果只完成第一步,第二步失败,钱会莫名其妙少了100元。
  • C (Consistency) 一致性:一致性也比较容易理解,就是说数据库要一直处于一致的状态,事务的运行不会改变数据库原本的一致性约束。例如现有完整性约束a+b=10,如果一个事务改变了a,那么必须得改变b,使得事务结束后依然满足a+b=10,否则事务失败。
  • I (Isolation) 独立性:所谓的独立性是指并发的事务之间不会互相影响,如果一个事务要访问的数据正在被另外一个事务修改,只要另外一个事务未提交,它所访问的数据就不受未提交事务的影响。比如现在有个交易是从A账户转100元至B账户,在这个交易还未完成的情况下,如果此时B查询自己的账户,是看不到新增加的100元的。
  • D (Durability) 持久性:持久性是指一旦事务提交后,它所做的修改将会永久的保存在数据库上,即使出现宕机也不会丢失。

结构化数据:指的是由二维表结构来逻辑表达和实现的数据,严格遵循数据格式与长度规范,也称作为行数据,因此关系型数据库完美契合结构化数据的特点例如:

非结构化数据:指的是数据结构不规则或不完整,没有任何预定义的数据模型,不方便用二维逻辑表来表现的数据,例如办公文档(Word)、文本、图片、HTML、各类报表、视频音频等。

半结构化数据:介于结构化与非结构化数据之间的数据就是半结构化数据了,它是结构化数据的一种形式,虽然不符合二维逻辑这种数据模型结构,但是包含相关标记,用来分割语义元素以及对记录和字段进行分层。例如

<person>
    <name>张三</name>
    <age>18</age>
    <phone>12345</phone>
</person>

使用关系型数据库的系统架构发展过程: 

关系型数据库的缺点

  • 高并发下IO压力大——数据按行存储,即使只针对其中某一列进行运算,也会将整行数据从存储设备中读入内存,导致IO较高 。
  • 为维护索引付出的代价大——为了提供丰富的查询能力,通常热点表都会有多个二级索引,一旦有了二级索引,数据的新增必然伴随着所有二级索引的新增,数据的更新也必然伴随着所有二级索引的更新,这不可避免地降低了关系型数据库的读写能力,且索引越多读写能力越差。
  • 为维护数据一致性付出的代价大——为了维护数据一致性,数据库就需要提供并发控制与故障恢复两种技术,前者用于减少并发异常,后者可以在系统异常的时候保证事务与数据库状态不会被破坏。对于并发控制,其核心思想就是加锁,无论是乐观锁还是悲观锁,只要提供的隔离级别越高,那么读写性能必然越差。
  • 水平扩展后带来的种种问题难处理——数据库做分库,做了分库之后,数据迁移(1个库的数据按照一定规则打到2个库中)、跨库join(订单数据里有用户数据,两条数据不在同一个库中)、分布式事务处理都是需要考虑的问题,尤其是分布式事务处理,业界当前都没有特别好的解决方案。
  • 表结构扩展不方便——数据库存储的是结构化数据,因此表结构schema是固定的,扩展不方便,如果需要修改表结构,需要执行DDL(data definition language)语句修改,修改期间会导致锁表,部分服务不可用。
  • 全文搜索功能弱——像like "%中国真伟大%",只能搜索到"2019年中国真伟大,爱祖国",无法搜索到"中国真是太伟大了"这样的文本,即不具备分词能力,且like查询在"%中国真伟大"这样的搜索条件下,无法命中索引,将会导致查询效率大大降低

总结:关系型数据库在高并发下的能力是有瓶颈的,尤其是写入/更新频繁的情况下,出现瓶颈的结果就是数据库CPU高、Sql执行慢、客户端报数据库连接池不够等错误,因此例如万人秒杀这种场景,我们绝对不可能通过数据库直接去扣减库存。

 

引入Nosql

引入一层缓存,每次读从缓存中读取,缓存中读取不到,再去数据库中取,取完之后再写入到缓存,对数据做好失效机制通常就没有大问题了。通常来说,缓存是性能优化的第一选择也是见效最明显的方案。

但是,缓存通常都是KV型存储且容量有限(基于内存),无法解决所有问题,于是再进一步的优化,我们继续引入其他NoSql:

 

KV型NoSql(代表----Redis)

KV型NoSql顾名思义就是以键值对形式存储的非关系型数据库

优点:

  • 数据基于内存,读写效率高;
  • KV型数据,时间复杂度为O(1),查询速度快

缺点:

  • 只能根据K查V,无法根据V查K;
  • 查询方式单一,只有KV的方式,不支持条件查询,多条件查询唯一的做法就是数据冗余,但这会极大的浪费存储空间;
  • 内存是有限的,无法支持海量数据存储;
  • 同样的,由于KV型NoSql的存储是基于内存的,会有丢失数据的风险

 

搜索型NoSql(代表----ElasticSearch)

搜索型NoSql的诞生正是为了解决关系型数据库全文搜索能力较弱的问题,ElasticSearch是搜索型NoSql的代表产品

全文搜索的原理是倒排索引,要说倒排索引我们先看下什么是正排索引

正排索引

假设有3个网页:
url1 -> “我爱北京”
url2 -> “我爱到家”
url3 -> “到家美好”
这是一个正排索引

然后我们对内容进行分词

url1 -> {我,爱,北京}
url2 -> {我,爱,到家}
url3 -> {到家,美好}

这是一个分词后的正排索引

倒排索引
我 -> {url1, url2}
爱 -> {url1, url2}
北京 -> {url1}
到家 -> {url2, url3}
美好 -> {url3}

这是分词后的倒排索引

可以看到通过上面的分词过程就可以解决上面提到全文搜索功能弱的问题并且效率也会更高。

优点:

  • 支持分词场景、全文搜索,这是区别于关系型数据库最大特点
  • 支持条件查询,支持聚合操作,类似关系型数据库的Group By,但是功能更加强大,适合做数据分析
  • 数据写文件无丢失风险,在集群环境下可以方便横向扩展,可承载PB级别的数据
  • 高可用,自动发现新的或者失败的节点,重组和重新平衡数据,确保数据是安全和可访问的

缺点:

  • 性能全靠内存来顶,也是使用的时候最需要注意的点,非常吃硬件资源、吃内存,大数据量下64G + SSD基本是标配
  • 读写之间有延迟,写入的数据差不多1s样子会被读取到,这也正常,写入的时候自动加入这么多索引肯定影响性能
  • 数据结构灵活性不高,ElasticSearch这个东西,字段一旦建立就没法修改类型了,假如建立的数据表某个字段没有加全文索引,想加上,那么只能把整个表删了再重建

 

列式NoSql(代表----HBase)

列式NoSql是基于列式存储的,列式NoSql和关系型数据库一样都有主键的概念,区别在于关系型数据库是按照行组织的数据:

行组织形式(可以看到即使phone字段没有,它也是占空间的)

列组织形式(把上述数据分了俩个表)

     

优点:

  • 查询时只有指定的列会被读取,不会读取所有列
  • 存储上节约空间,Null值不会被存储,一列中有时候会有很多重复数据(尤其是枚举数据,性别、状态等),这类数据可压缩,行式数据库压缩率通常在3:1~5:1之间,列式数据库的压缩率一般在8:1~30:1左右
  • 列数据被组织到一起,一次磁盘IO可以将一列数据一次性读取到内存中

对数据压缩的解释:

缺点:

  • HBase是Hadoop生态的一部分,因此它本身是一款比较重的产品,依赖很多Hadoop组件,数据规模不大没必要用,运维还是有点复杂的
  • KV式,不支持条件查询,或者说条件查询非常非常弱吧,HBase在Scan扫描一批数据的情况下还是提供了前缀匹配这种API的,条件查询除非定义多个RowKey做数据冗余
  • 不支持分页查询,因为统计不了数据总数

 

文档型NoSql(代表----MongoDB)

文档型NoSql指的是将半结构化数据存储为文档的一种NoSql,文档型NoSql通常以JSON或者XML格式存储数据,因此文档型NoSql是没有Schema的,由于没有Schema的特性,我们可以随意地存储与读取数据,因此文档型NoSql的出现是解决关系型数据库表结构扩展不方便的问题的

例如下图:关系型数据库是按部就班地每个字段一列存,在MongDB里面就是一个JSON字符串存储。

优点:

  • 没有预定义的字段,扩展字段容易
  • 相较于关系型数据库,读写性能优越,命中二级索引的查询不会比关系型数据库慢,对于非索引字段的查询则是全面胜出

缺点:

  • 不支持事务操作,虽然Mongodb4.0之后宣称支持事务,但是效果待观测
  • 多表之间的关联查询不支持(虽然有嵌入文档的方式),join查询还是需要多次操作
  • 空间占用较大,这个是MongDB的设计问题,空间预分配机制 + 删除数据后空间不释放,只有用db.repairDatabase()去修复才能释放
  • 目前没发现MongoDB有关系型数据库例如MySql的Navicat这种成熟的运维工具(比较适合处理那些没有join、没有强一致性要求且表Schema会常变化的数据)

 

总结:

如何选择使用关系型数据库还是非关系型数据库?

  1. 不多解释应该都理解,非关系型数据库都是通过牺牲了ACID特性来获取更高的性能的,假设两张表之间有比较强的一致性需求,那么这类数据是不适合放在非关系型数据库中的。
  2. 核心数据不走非关系型数据库,例如用户表、订单表,但是这有一个前提,就是这一类核心数据会有多种查询模式,例如用户表有ABCD四个字段,可能根据AB查,可能根据AC查,可能根据D查,假设核心数据,但是就是个KV形式,比如用户的聊天记录,那么HBase一存就完事了。
  3. 非核心数据尤其是日志、流水一类中间数据千万不要写在关系型数据库中(写远高于读,写入量巨大)一旦使用关系型数据库作为存储引擎,将大大降低关系型数据库的能力,正常读写QPS不高的核心服务会受这一类数据读写的拖累
  4. 选型一定要结合实际情况而不是照本宣科,如:企业发展之初,明明一个关系型数据库就能搞定且支撑一年的架构,搞一套大而全的技术方案出来;有一些数据条件查询多,更适合使用ElasticSearch做存储降低关系型数据库压力,但是公司成本有限,这种情况下这类数据可以尝试继续使用关系型数据库做存储有一类数据格式简单,就是个KV类型且增长量大,但是公司没有HBase这方面的人才,运维上可能会有一定难度,出于实际情况考虑,可先用关系型数据库顶一阵子

如何从多种非关系型数据库中选择合适自己的?

 

引用:https://www.cnblogs.com/xrq730/p/11039384.html

版权声明
本文为[呼叫冰河谷]所创,转载请带上原文链接,感谢
https://blog.csdn.net/hzkcsdnmm/article/details/114385639

随机推荐