Skip to main content

其他数据库

其他数据库主要有图形数据库和文档数据库

图形数据库(Neo4j)

图形:图形数据库旨在轻松构建和运行与高度连接的数据集一起使用的应用程序。图形数据库的典型使用案例包括社交网络、推荐引擎、欺诈检测和知识图形。热门图形数据库包括 Neo4j 和 Giraph。图形数据库专门用于存储和导航关系。关系是图形数据库中的一等公民,图形数据库的大部分价值都源自于这些关系。图形数据库使用节点来存储数据实体,并使用边缘来存储实体之间的关系。边缘始终有一个开始节点、结束节点、类型和方向,并且边缘可以描述父子关系、操作、所有权等。一个节点可以拥有的关系的数量和类型没有限制。

图形数据库中的图形可依据具体的边缘类型进行遍历,或者也可对整个图形进行遍历。在图形数据库中,遍历联结或关系非常快,因为节点之间的关系不是在查询时计算的,而是留存在数据库中。在社交网络、推荐引擎和欺诈检测等使用案例中,您需要在数据之间创建关系并快速查询这些关系,此时,图形数据库更具优势。

图数据库如何表达数据?或者其建模方式

图数据库使用图模型来操作数据。目前使用的图模型有 3 种,分别是属性图(Property Graph)、资源描述框架(RDF)三元组和超图(HyperGraph)。现在较为知名的图数据库主要是基于属性图,更确切得说是带标签的属性图(Labeled-Property Graph),当然标签不是必须的。

属性图由顶点(圆圈)、边(箭头)、属性(key:value)和标签组成,顶点和边可以有标签,比如顶点的标签是 User,边的标签是 FOLLOWS。图中标签为 User 的顶点有 name 属性,属性值为 Johan 或 Peter 或 Emil。边表示了他们的关注关系。图中标签为 FOLLOWS 的边是单向边,如果是相互关注了,那么需要 2 条边表示。

为什么需要图数据库,相比关系型数据库等有什么优势?

因为关系型数据库不擅长处理数据之间的关系。我们举最经典的社交网络中查询的性能作为对比。

一个社交网络,图中包括了朋友、同事、夫妻和恋人等多种关系。有人曾做过一个测试:在一个包含 100w 人,每人约有 50 个朋友的社交网络中找到最大深度为 5 的朋友的朋友。

测试结果如下:

深度为 2 时(即朋友的朋友),两种数据库性能相差不是很明显;

深度为 3 时,很明显,关系型数据库的响应时间 30s,已经变得不可接受了;

深度到 4 时,关系数据库需要近半个小时才能返回结果,已经妄称在线数据处理系统了;

深度到 5 时,关系型数据库已经掉入深渊。而对于图数据库 Neo4J,深度从 3 到 5,其响应时间均在 3 秒以内。

可以看出,对于图数据库来说,数据量越大,越复杂的关联查询,约有利于体现其优势。从深度为 4/5 的查询结果我们可以看出,图数据库返回了整个社交网络一半以上的人数。

除了性能好,图数据库还有其他优势吗?

除了很显而易见的性能优势外,灵活性和敏捷性也是图数据库相比关系型数据库的重要优势。图天生就是灵活可扩展的,可以对已存在的图结构增加新的边、节点、标签和子图,但却不会破坏现有的查询和应用程序的功能。这就使我们无需在项目之初,对数据的真实模样和复杂度缺乏了解的情况下被迫设计成最终而完整的数据模型,往往这样的模型并不是最终和完整的。

另一方面,有些业务本身就是灵活多变的,或者说敏捷的。使用图数据库(或其他 NoSQL 数据库,比如 MongoDB)可以快速跟上业务的变化而不需要进行 Schema 变更等代价不菲的管理操作。

图数据库怎么使用,用 SQL 做增删改查吗?

图数据库不使用最传统的 SQL 作为 CRUD 语言,原因是 SQL 作为关系型数据库的查询语言,其也不擅长表达 Join 等关系查询和操作,在需要做多层的关系 Join 查询时,SQL 往往冗长而难以直观得理解。这是为什么不采用大家最为熟知的 SQL 却要引入新的图查询语言的主要原因。举个对比的例子:

在英文中“I love my younger sister as well as my grandmother on my father’s side”,与中文的“我爱我的妹妹和奶奶” 是一样的意思,但是在简洁程度上中文远远好于英文。(6 个词,9 个字) vs (14 个词, 70 个字)

也就是说,在图数据库中使用专门的图查询语言比使用 SQL 更加高效。目前主流的图查询语言是 Cypher 和 Gremlin。

目前有哪些比较知名的图数据库?

Neo4J 最主流的图数据库,相比其他数据库更加成熟,Neo4J 使用 Java 开发,支持 ACID,最新版本是 3.3.5。每个版本均有社区版和企业版,其中社区版是免费版,基于 GPLv3 协议开源,但局限于单机部署,功能受限。企业版包括了 Neo4J 所有功能,包括主从复制用于高可用和读写分离,可视化管理工具等,但增加了商业协议,需付费使用。Neo4J 不是分布式数据库,扩展性不是其优势。但它是一种原生的图数据库,同时也具备了图分析引擎的能力。应该说 Neo4J 是目前使用最为广泛的图数据库,大量介绍图数据库的书籍都是以 Neo4J 为基础来介绍的。

Neo4J 使用 Cypher 作为图数据库查询语言,由于 Neo4J 的成功,Cypher 目前被大多数图数据库所支持。Cypher 语言例子如下(找出所有 Johan 所关注的人所关注的人,该人也是 Johan 关注的人):

MATCH (a:Person {name:'Johan'})-[:FOLLOWS]->(b)-[:FOLLOWS]->(c),        (a)-[:FOLLOWS]->(c)  RETURN b, c

原生图数据库,这是什么意思?

原生图处理指的是利用了免索引邻接的图数据库。免索引邻接是指通过边关联的 2 个节点,其彼此指向是物理的,也就是通过边访问一个节点时,该边保存的就是目标节点在磁盘上的物理地址,这样就需要通过索引去找到目标节点,如果边很多的时候,对性能提升很有帮助。

一、社交网络应用

社交是人与人之间的连接,以图数据模型为内在的图数据库天生适用于明显的以联系为中心的领域。在社交网络中使用图数据库可以方便得识别人/群组和他们交流的事物之间的直接或间接的联系,使用户能够高效地对其他人或事物进行打分、评论、发现彼此存在的关系和共同关系的事情。可以更加直观得了解社交网络中人与人之间如何互动、如何关联、如何以群组的形式来做事情或选择。

社交网络是最基础的图模型,在此基础上可以叠加更多的内容,比如个人的喜好、购买过的物品、日常的生活方式等,从而演化出更高级的图数据库应用模式,比如实时推荐系统。

二、实时推荐

在零售、招聘、情绪分析、搜索和知识管理领域,社交网络和推荐引擎可以提供关键的差异化能力,有很多种办法可以实现推荐,但使用图数据库在实时性和效率上有其特有的优势。推荐算法在人和事物之间建立联系,而联系建立的基础是用户的行为,比如购买、生产、消费、打分或评论有关资源等行为。推荐引擎可以识别出某些资源会吸引特定个人或群体,或者某些个人或群体可能对特定资源感兴趣。

一个有效的推荐依赖于对事物之间关联的理解,同时也依赖于这些关联的质量和强度,而属性图是所有这些关系密切、关联紧密的数据结构的最佳表达方式。用图数据库存储和查询这些数据使得应用程序可以为最终用户呈现实时结果,反映数据最新的变化,而不是返回给用户那些预计算的状态结果。

三、地理空间管理

地理空间类的应用程序包括公路网、铁路网等,地理空间操作依赖于特定的数据结构,简单的加权带方向的联系,复杂到空间索引如 R 树。和索引一样,这些数据结构天生就以图的形式呈现,尤其是层级结构,非常适合图数据库。

总的来说,通信、物流、旅游已经路由计算相关领域的地理空间应用经常会使用图数据库。

四、主数据管理(Master Data Managerment)

在企业或组织中,主数据管理(MDM)包括的数据涉及用户、客户、产品、供应商、部门、区域、站点、成本中心和业务单元等。这些数据来源可能是多种多样的,MDM 用来识别、清洗、存储和管理这些数据。其关键问题包括谁组织结构的变化、企业合并和业务规则的变化来管理这些变化;融合新的数据源,用外部源数据补充已有的数据;解决报告需求、鉴定需求和商业智能客户的需求;当数据的值和模式变化时对数据进行版本管理。图数据库的数据模型高效匹配 MDM 的快速演变和不断变化的业务需求。

五、网络和数据中心管理

图数据库已经成功地使用在了电信、网络管理和分析、云平台管理、数据中心和 IT 资产管理以及网络影响分析等领域。在这些领域里,他们将影响分析和问题解决的时间时间从数天数小时减少到了分钟级甚至秒级。面对不断变化的网络模式,图数据库的性能和灵活性都是它适合这些领域应用的重要因素。

六、授权和访问控制

图数据库可以存储那些复杂的、高度关联的、跨越数十亿参与者和资源的访问控制结构。尤其适用于内容管理、联合授权服务、社交网络偏好已经软件服务化提供。将这些系统从关系型数据库切换到图数据库后,性能从分钟级提升到毫秒级。

上面仅列举了部分例子,除此之外,图数据库产品还广泛用在金融和保险行业反欺诈、风控,电商和社交类产品防机器人作弊等领域。

文档数据库(MongoDB)

文档:在应用程序代码中,数据通常表示为对象或 JSON 文档,因为对开发人员而言它是高效和直观的数据模型。文档数据库让开发人员可以使用他们在其应用程序代码中使用的相同文档模型格式,更轻松地在数据库中存储和查询数据。文档和文档数据库的灵活、半结构化和层级性质允许它们随应用程序的需求而变化。文档模型可以很好地与目录、用户配置文件和内容管理系统配合使用,其中每个文档都是唯一的,并会随时间而变化。

文档数据库是一种非关系数据库,旨在将数据作为类 JSON 文档存储和查询。文档数据库让开发人员可以使用他们在其应用程序代码中使用的相同文档模型格式,更轻松地在数据库中存储和查询数据。文档和文档数据库的灵活、半结构化和层级性质允许它们随应用程序的需求而变化。文档模型可以很好地与目录、用户配置文件和内容管理系统等使用案例配合使用,其中每个文档都是唯一的,并会随时间而变化。文档数据库支持灵活的索引、强大的临时查询和文档集合分析。

基本用例

Python可以使用pymongo库来与MongoDB交互。

pip install pymongo

然后,使用以下代码来连接到MongoDB:

from pymongo import MongoClient

# 创建MongoDB的连接
client = MongoClient('localhost', 27017)

# 连接到你的数据库
db = client['mydatabase']

以下是一些基本的增删改查示例:

创建文档

# 选择一个集合
collection = db['mycollection']

# 创建一个文档
document = {
"name": "John",
"age": 30,
"city": "New York"
}

# 插入文档到集合中
result = collection.insert_one(document)

# 打印插入文档的_id
print(result.inserted_id)

读取文档

# 查找单个文档
document = collection.find_one({"name": "John"})
print(document)

# 查找多个文档
for document in collection.find({"age": {"$gt": 20}}):
print(document)

更新文档

# 更新单个文档
collection.update_one({"name": "John"}, {"$set": {"age": 31}})

# 更新多个文档
collection.update_many({"age": {"$gt": 20}}, {"$inc": {"age": 1}})

删除文档

# 删除单个文档
collection.delete_one({"name": "John"})

# 删除多个文档
collection.delete_many({"age": {"$gt": 20}})

面试常问

综合考察对数据库的理解

Nosql

NoSQL(Not only SQL)是对不同于传统的关系数据库的数据库管理系统的统称,即广义地来说可以把所有不是关系型数据库的数据库统称为 NoSQL。

NoSQL 数据库专门构建用于特定的数据模型,并且具有灵活的架构来构建现代应用程序。NoSQL 数据库使用各种数据模型来访问和管理数据。这些类型的数据库专门针对需要大数据量、低延迟和灵活数据模型的应用程序进行了优化,这是通过放宽其他数据库的某些数据一致性限制来实现的。

数十年来,用于应用程序开发的主要数据模型是由关系数据库(如 Oracle、DB2、SQL Server、MySQL 和 PostgreSQL)使用的关系数据模型。直到 21 世纪中后期,才开始大规模采用和使用其他数据模型。为了对这些新类别的数据库和数据模型进行区分和分类,创造了术语“NoSQL”。通常术语“NoSQL”与“非关系”可互换使用。

NoSQL 的 BASE 原则:Basically Available, Soft-state, Eventually Consistent。 由 Eric Brewer 定义。BASE 是 NoSQL 数据库通常对可用性及一致性的弱要求原则:

  • Basically Availble --基本可用
  • Soft-state --软状态/柔性事务。 "Soft state" 可以理解为"无连接"的, 而 "Hard state" 是"面向连接"的
  • Eventual Consistency -- 最终一致性, 也是是 ACID 的最终目的。

BASE 模型是传统 ACID 模型的反面,不同于 ACID,BASE 强调牺牲高一致性,从而获得可用性,数据允许在一段时间内的不一致,只要保证最终一致就可以了.

MVCC

MVCC 是多版本并发控制机制,顾名思义支持 MVCC 的数据库表中每一行数据都可能存在多个版本,对数据库的任何修改的提交都不会直接覆盖之前的数据,而是产生一个新的版本与老版本共存,通过读写数据时读不同的版本来避免加锁阻塞。

使用锁和锁协议来实现相应的隔离级别来进行并发控制会造成事务阻塞,导致并发性能会受到一定的影响。而多版本并发控制使得对同一行记录做读写的事务之间不用相互阻塞等待(写写还是要阻塞等待,因为事务对数据进行更新时会加上排他锁),提高了事务的并发能力,可以认为 MVCC 是一种解决读写阻塞等待的行级锁。

MVCC 的重要特性: (1)MVCC 只支持 RC(读取已提交)和 RR(可重复读)隔离级别。 (2)MVCC 能解决脏读、不可重复读问题,不能解决丢失更新问题和幻读问题。 (3)MVCC 是用来解决读写操作之间的阻塞问题。使得在并发读写数据库时,可以做到在读操作时不用阻塞写操作,写操作也不用阻塞读操作,提高了数据库并发读写的性能。

innodb

InnoDB 会为每个使用 InnoDB 存储引擎的表添加三个隐藏字段,用于实现数据多版本以及聚集索引,他们的作用如下:

  • DB_TRX_ID(6 字节): 它是最近一次更新或者插入或者删除该行数据的事务 ID(若是删除,则该行有一个删除位更新为已删除。但并不是真正的进行物理删除,当 InnoDB 丢弃为删除而编写的更新撤消日志记录时,它才会物理删除相应的行及其索引记录。此删除操作称为清除,速度非常快)
  • DB_ROLL_PTR(7 字节): 回滚指针,指向当前记录行的 undo log 信息(指向该数据的前一个版本数据)
  • DB_ROW_ID(6 字节): 随着新行插入而单调递增的行 ID。InnoDB 使用聚集索引,数据存储是以聚集索引字段的大小顺序进行存储的,当表没有主键或唯一非空索引时,innodb 就会使用这个行 ID 自动产生聚簇索引。如果表有主键或唯一非空索引,聚簇索引就不会包含这个行 ID 了。这个 DB_ROW_ID 跟 MVCC 关系不大。

ORM

对象关系映射(Object Relational Mapping,简称 ORM)模式是一种为了解决面向对象与关系数据库存在的互不匹配的现象的技术。

简单的说,ORM 是通过使用描述对象和数据库之间映射的元数据,将程序中的对象自动持久化到关系数据库中。

那么,到底如何实现持久化呢?一种简单的方案是采用硬编码方式,为每一种可能的数据库访问操作提供单独的方法。

优点

与传统的数据库访问技术相比,ORM 有以下优点:

  • 开发效率更高
  • 数据访问更抽象、轻便
  • 支持面向对象封装

缺点

  • 降低程序的执行效率
  • 思维固定化

从系统结构上来看,采用 ORM 的系统一般都是多层系统,系统的层次多了,效率就会降低。ORM 是一种完全的面向对象的做法,而面向对象的做法也会对性能产生一定的影响 N+1 问题

N+1 是 ORM(对象关系映射)关联数据读取中存在的一个问题。

假设现在有一个用户表(User)和一个余额表(Balance),这两个表通过 user_id 进行关联。现在有一个需求是查询年龄大于 18 岁的用户,以及用户各自的余额。

这个问题并不难,但对于新手而言,可能常常会犯的一个错误就是在循环中进行查询。

$users = User::where("age", ">", 18)->select();
foreach($users as $user){
$balance = User::getFieldByUserId($user->user_id, "balance");
$user['balance'] = $balance;
}

通过 Mysql 查询日志,可以看到查询用户表是一次,因为有四个符合该条件的用户,查询用户表关联的余额表是四次。

N+1 问题就是这样产生的:查询主表是一次,查询出 N 条记录,根据这 N 条记录,查询关联的副(从)表,共需要 N 次。所以,应该叫 1+N 问题更合适一些。

其实,如果稍微了解一点 SQL,根本不用这么麻烦,直接使用 IN 一次就搞定了。

对于这类问题,ORM 其实为我们提供了相应的方案,那就是使用『预加载功能』。

使用 with()方法指定想要预加载的关联:

$users = User::where("age", ">", 18)
->with("hasBalance")
->select();

hasBalance 这个方法让 User 模型与 Balance 模型进行一对一关联,总查询次数由原来的 1+N 变成了现在的 1+1。

Transaction

事务(Transaction)是一个对数据库执行工作单元。

事务(Transaction)是以逻辑顺序完成的工作单位或序列,可以是由用户手动操作完成,也可以是由某种数据库程序自动完成。

事务(Transaction)是指一个或多个更改数据库的扩展。例如,如果您正在创建一个记录或者更新一个记录或者从表中删除一个记录,那么您正在该表上执行事务。重要的是要控制事务以确保数据的完整性和处理数据库错误。实际上,您可以把许多的 SQLite 查询联合成一组,把所有这些放在一起作为事务的一部分进行执行。

ACID

事务(Transaction)具有以下四个标准属性,通常根据首字母缩写为 ACID:

  • 原子性(Atomicity):确保工作单位内的所有操作都成功完成,否则,事务会在出现故障时终止,之前的操作也会回滚到以前的状态。
  • 一致性(Consistency):确保数据库在成功提交的事务上正确地改变状态。
  • 隔离性(Isolation):使事务操作相互独立和透明。
  • 持久性(Durability):确保已提交事务的结果或效果在系统发生故障的情况下仍然存在。

四个特性(ACID),其中原子性是如何实现的?

从 redolog 的角度

规定在执行这些需要保证原子性的操作时必须以组的形式来记录的 redo 日志,在进行系统崩溃重启恢复时,针对某个组中的 redo 日志,要么把全部的日志都恢复掉,要么一条也不恢复。在该组中的最后一条 redo 日志后边加上一条特殊类型的 redo 日志,该类型名称为 MLOG_MULTI_REC_END,type 字段对应的十进制数字为 31,该类型的 redo 日志结构很简单,只有一个 type 字段。所以某个需要保证原子性的操作产生的一系列 redo 日志必须要以一个类型为 MLOG_MULTI_REC_END 结尾。

从 undolog 的角度

InnoDB 存储引擎在实际进行增、删、改一条记录时,都需要先把对应的 undo 日志记下来。一般每对一条记录做一次改动,也可能会对应着 2 条 undo 日志:(每对一条记录的主键值做改动时,会记录 2 条 undo 日志,因为会有对该记录进行 delete mark 操作前,会记录一条类型为TRX_UNDO_DEL_MARK_REC的 undo 日志;之后插入新记录时,会记录一条类型为TRX_UNDO_INSERT_REC的 undo 日志)

一次事务如果有很多 undolog,会进行编号,比如 undolog 1, 2, 3 就是 undo no

当我们向某个表中插入一条记录时,实际上需要向聚簇索引和所有的二级索引都插入一条记录。不过记录 undo 日志时,我们只需要考虑向聚簇索引插入记录时的情况就好了,因为其实聚簇索引记录和二级索引记录是一一对应的,我们在回滚插入操作时,只需要知道这条记录的主键信息,然后根据主键信息做对应的删除操作,做删除操作时就会顺带着把所有二级索引中相应的记录也删除掉。

事务的隔离级别

在实际应用中,数据库中的数据是要被多个用户共同访问的,在多个用户同时操作相同的数据时,可能就会出现一些事务的并发问题,具体如下。

  • 脏读 指一个事务读取到另一个事务未提交的数据。
  • 不可重复读 指一个事务对同一行数据重复读取两次,但得到的结果不同。
  • 虚读/幻读 指一个事务执行两次查询,但第二次查询的结果包含了第一次查询中未出现的数据。
  • 丢失更新 指两个事务同时更新一行数据,后提交(或撤销)的事务将之前事务提交的数据覆盖了。

丢失更新可分为两类,分别是第一类丢失更新和第二类丢失更新。

  • 第一类丢失更新是指两个事务同时操作同一个数据时,当第一个事务撤销时,把已经提交的第二个事务的更新数据覆盖了,第二个事务就造成了数据丢失。
  • 第二类丢失更新是指当两个事务同时操作同一个数据时,第一个事务将修改结果成功提交后,对第二个事务已经提交的修改结果进行了覆盖,对第二个事务造成了数据丢失。

为了避免上述事务并发问题的出现,在标准的 SQL 规范中定义了四种事务隔离级别,不同的隔离级别对事务的处理有所不同。这四种事务的隔离级别如下。

  • Read Uncommitted(读未提交) 一个事务在执行过程中,既可以访问其他事务未提交的新插入的数据,又可以访问未提交的修改数据。如果一个事务已经开始写数据,则另外一个事务不允许同时进行写操作,但允许其他事务读此行数据。此隔离级别可防止丢失更新。
  • Read Committed(读已提交) 一个事务在执行过程中,既可以访问其他事务成功提交的新插入的数据,又可以访问成功修改的数据。读取数据的事务允许其他事务继续访问该行数据,但是未提交的写事务将会禁止其他事务访问该行。此隔离级别可有效防止脏读。
  • Repeatable Read(可重复读取) 一个事务在执行过程中,可以访问其他事务成功提交的新插入的数据,但不可以访问成功修改的数据。读取数据的事务将会禁止写事务(但允许读事务),写事务则禁止任何其他事务。此隔离级别可有效防止不可重复读和脏读。
  • Serializable(可串行化) 提供严格的事务隔离。它要求事务序列化执行,事务只能一个接着一个地执行,不能并发执行。此隔离级别可有效防止脏读、不可重复读和幻读。但这个级别可能导致大量的超时现象和锁竞争,在实际应用中很少使用。

一般来说,事务的隔离级别越高,越能保证数据库的完整性和一致性,但相对来说,隔离级别越高,对并发性能的影响也越大。因此,通常将数据库的隔离级别设置为 Read Committed,即读已提交数据,它既能防止脏读,又能有较好的并发性能。虽然这种隔离级别会导致不可重复读、幻读和第二类丢失更新这些并发问题,但可通过在应用程序中采用悲观锁和乐观锁加以控制。

事务控制

使用下面的命令来控制事务:

  • BEGIN TRANSACTION:开始事务处理。
  • COMMIT:保存更改,或者可以使用 END TRANSACTION 命令。
  • ROLLBACK:回滚所做的更改。

事务控制命令只与 DML 命令 INSERT、UPDATE 和 DELETE 一起使用。他们不能在创建表或删除表时使用,因为这些操作在数据库中是自动提交的。

什么是脏读?什么是幻读?

脏读 :脏读就是指当一个事务正在访问数据,并且对数据进行了修改,而这种修改还没有提交到数据库中,这时,另外一个事务也访问这个数据,然后使用了这个数据。

幻读 : 是指当事务不是独立执行时发生的一种现象,例如第一个事务对一个表中的数据进行了修改,这种修改涉及到表中的全部数据行。 同时,第二个事务也修改这个表中的数据,这种修改是向表中插入一行新数据。那么,以后就会发生操作第一个事务的用户发现表中还有没有修改的数据行,就好象 发生了幻觉一样。例如,一个编辑人员更改作者提交的文档,但当生产部门将其更改内容合并到该文档的主复本时,发现作者已将未编辑的新材料添加到该文档中。 如果在编辑人员和生产部门完成对原始文档的处理之前,任何人都不能将新材料添加到文档中,则可以避免该问题。

mysql 的默认隔离级别是?能解决脏读和幻读吗?

mysql 的默认隔离级别是可重复读,也有企业生产环境是读已提交

读未提交(Read UnCommitted),简称为 RU; 最低的隔离级别,允许读取尚未提交的数据变更,可能会导致脏读、幻读或不可重复读。

读已提交(Read Commited),简称为 RC; 允许读取并发事务已经提交的数据,可以阻止脏读,但是幻读或不可重复读仍有可能发生。

可重复读(Repeatable Read),简称为 RR;对同一字段的多次读取结果都是一致的,除非数据是被本身事务自己所修改,可以阻止脏读和不可重复读,但幻读仍有可能发生。

串行化(Serializable)最高的隔离级别,完全服从 ACID 的隔离级别。所有的事务依次逐个执行,这样事务之间就完全不可能产生干扰,也就是说,该级别可以防止脏读、不可重复读以及幻读。

如何解决幻读?

MVCC 加上间隙锁的方式 (1)在快照读读情况下,mysql 通过 mvcc 来避免幻读。 (2)在当前读读情况下,mysql 通过 next-key 来避免幻读。锁住某个条件下的数据不能更改。

索引的底层实现?

相较于 B 树,B+树的优势是什么?

1.单一节点存储更多的元素,使得查询的 IO 次数更少;

2.所有查询都要查找到叶子节点,查询性能稳定;

3.所有叶子节点形成有序链表,便于范围查询。

首先,B+树的查找和B树一样,类似于二叉查找树。起始于根节点,自顶向下遍历树,选择其分离值在要查找值的任意一边的子指针。在节点内部典型的使用是二分查找来确定这个位置。

不同的是,B+树中间节点没有卫星数据(索引元素所指向的数据记录),只有索引,而B树每个结点中的每个关键字都有卫星数据;这就意味着同样的大小的磁盘页可以容纳更多节点元素,在相同的数据量下,B+树更加“矮胖”,IO操作更少。

其次,因为卫星数据的不同,导致查询过程也不同;B树的查找只需找到匹配元素即可,最好情况下查找到根节点,最坏情况下查找到叶子结点,所说性能很不稳定,而B+树每次必须查找到叶子结点,性能稳定。

在范围查询方面,B+树的优势更加明显:B 树的范围查找需要不断依赖中序遍历。首先二分查找到范围下限,在不断通过中序遍历,知道查找到范围的上限即可。整个过程比较耗时。而 B+树的范围查找则简单了许多。首先通过二分查找,找到范围下限,然后同过叶子结点的链表顺序遍历,直至找到上限即可,整个过程简单许多,效率也比较高。