- 一、数据库
- 二、MySQL
- 1. 存储引擎
- 2. 索引
- 3. 索引底层存储(B树、B+树、红黑树、AVL树)
- 4. 版本变迁及特性
- 5. 事务隔离
- 事务隔离相关的几个问题如下:
- 6.MVCC
- 7.NoSQL 和关系数据库的区别?(2018-4-16-lxy)
- 8.Mysql 数据库中怎么实现分页?(2018-4-23-zcz)
- 9.sql 语句怎么看效率?(2018-4-23-zcz)
- 10.虽然UPDATE、DELETE 语句的写法基本固定,但是还是对UPDATE 语句给点建议:
- 11.数据库的设计?(2018-5-1-lxy)
- 12.存储过程和函数的区别?(2018-5-1-lxy)
- 14.Mysql 日志(2018-5-1-lyf)
- 面试题一:知道mysql的事务隔离吗?/事务隔离分哪几个级别?/事务隔离性怎么保证/...**
- 15. Mysql和MongoDB的区别
- 三、MongoDB
- 四、Redis相关
- 五、列式数据库
- 二、MySQL
一、数据库
今天的主要内容集中在面试过程中的数据库部分;互联网公司Python相关岗位面试中大多数会有数据库相关的面试问题。
大家认为什么是数据库呢?
数据库简而言之是一种电子化的文件柜,用户可以对文件中的数据进行增删改查;当前互联网中,最常见的数据模型主要有两种:关系型数据库和非关系型数据库。
关系型数据库常见的有MySQL,Oracle, Postgrel, MariaDB, SQL Server等;非关系型数据库(nosql, not only sql)有Redis, Memcached, MongoDB, Hbase等。
1. 关系型数据库
关系型数据库优点主要在三方面:易用性(都是使用表结构,格式一致),使用方便(SQL语言),支持复杂查询(多表之间复杂查询);其缺陷在于三块:读写性能较差,尤其是海量数据的高并发读写;二是因为是固定的表结构导致其灵活度不高,三是高并发的情况下硬盘IO容易成为瓶颈;
2. 非关系型数据库
非关系型数据库主要的优势如下:
1) 格式灵活:存储数据格式支持key-value,文档,图片等;
2) 高扩展性:很容易进行集群扩展,适应海量数据增减;
3) 速度快:nosql可以使用硬盘和随机存储器作为存储介质,同时其设计理念之初一般便适合海量数据的高并发读写;
4) 成本低:nosql数据库部署简单,基本都是开源软件;
二、MySQL
关系型数据库中大家应该mysql接触的比较多。mysql面试中一般会有几大类易考点:
1. 存储引擎
查看MySQL支持哪些存储引擎可以在登录mysql后执行show engines;
当前常用的mysql存储引擎有InnoDB, MyIsam, Merge, Memory等。
其中使用最为广泛的是InnoDB存储引擎,InnoDB是一种事务性的存储引擎,一般如果需要事务支持,并且需要较高的读写频率,推荐使用InnoDB;
MyIsam不支持事务,也不支持外键,但访问速度很快,每个MyIsam表在磁盘上存储有三个文件(.frm存储表定义,.myd存储数据,.myi存储索引);
Merge存储引擎是一种MyIsam表的集合,这些MyIsam表结构必须完全一致,说白了,merge表只是一堆MyIsam表的集合器,merge表中并没有数据,对merge表的增删改查操作实际上是对MyIsam表的操作;删除merge表时,只是删除merge表的定义,对内部数据没有影响;
Memory存储引擎的逻辑存储介质是内存,但memory表中存储的数据必须是长度不变的格式,同时由于内存介质特性,当宕机或出现其他故障时,很容易出现数据损失的情况;在实际的公司生产线上使用很少;
2. 索引
大家应该都去过图书馆,比如深圳图书馆藏书400万册,我们怎么在这海量的图书中找到自己真正想找的书呢?首先通过系统关键词搜索找到书的索引号,如T520.13等;而在计算机中也是一样,随着数据的增多,如果表中没有合适索引,单表的查询性能基本也就万这个级别了,每一次查询都需要进行全表扫描(即扫描该表中所有的记录),效率低下;在MySQL中索引根据存储的方式区分又分为聚集索引和非聚集索引两种;聚集索引数据的存放顺序于索引顺序是一致的。即只要索引是相邻的,那么索引所对应的数据也一定是相邻的存放在磁盘上。这样做的好处是什么呢?设想一下做范围查询时,比如查询1000-10000的主键ID,又或者以a,b,c开头的用户名,如果是聚集索引的话,实际情况只需要一次磁盘IO。
而非聚集索引的逻辑顺序与磁盘上的物理顺序不同,非聚集索引的数据在逻辑上也是连续的,但其记录的逻辑顺序和磁盘上记录的物理顺序没有任何直接联系。有点类似于大家以前使用新华字典时根据偏旁部首查字典,查偏旁部首对应的连着的两个字时目录部分是连续的,但详情页实际的字却很有可能是不挨着的。
根据唯一性区分又分为:
a. 普通索引
这是最基本的索引,它没有任何限制,比如上文中为title字段创建的索引就是一个普通索引,MyIASM中默认的BTREE类型的索引,也是我们大多数情况下用到的索引。
CREATE INDEX index_name ON table(column(length))
b. 唯一索引
与普通索引类似,不同的就是:索引列的值必须唯一,但允许有空值(注意和主键不同)。如果是组合索引,则列值的组合必须唯一,创建方法和普通索引类似。
CREATE UNIQUE INDEX indexName ON table(column(length))
c. 组合索引(最左前缀)
平时用的SQL查询语句一般都有比较多的限制条件,所以为了进一步榨取MySQL的效率,就要考虑建立组合索引。例如上表中针对title和time建立一个组合索引:ALTER TABLE article ADD INDEX index_titme_time (title(50),time(10))。建立这样的组合索引,其实是相当于分别建立了下面两组组合索引:
–title,time
–title
为什么没有time这样的组合索引呢?这是因为MySQL组合索引“最左前缀”的结果。简单的理解就是只从最左面的开始组合。并不是只要包含这两列的查询都会用到该组合索引,如下面的几个SQL所示:
SELECT * FROM article WHREE title='测试' AND time=1234567890;
SELECT * FROM article WHREE utitle='测试';
SELECT * FROM article WHREE time=1234567890;
3. 索引底层存储(B树、B+树、红黑树、AVL树)
二叉查找树
简介
二叉查找树也称为有序二叉查找树,满足二叉查找树的一般性质,是指一棵空树具有如下性质:
任意节点左子树不为空,则左子树的值均小于根节点的值.
任意节点右子树不为空,则右子树的值均大于于根节点的值.
任意节点的左右子树也分别是二叉查找树.
没有键值相等的节点.
局限性及应用
一个二叉查找树是由n个节点随机构成,所以,对于某些情况,二叉查找树会退化成一个有n个节点的线性链.如下图:
b图为一个普通的二叉查找树,大家看a图,如果我们的根节点选择是最小或者最大的数,那么二叉查找树就完全退化成了线性结构,因此,在二叉查找树的基础上,又出现了AVL树,红黑树,它们两个都是基于二叉查找树,只是在二叉查找树的基础上又对其做了限制.
AVL树
简介
AVL树是带有平衡条件的二叉查找树,一般是用平衡因子差值判断是否平衡并通过旋转来实现平衡,左右子树树高不超过1,和红黑树相比,它是严格的平衡二叉树,平衡条件必须满足(所有节点的左右子树高度差不超过1).不管我们是执行插入还是删除操作,只要不满足上面的条件,就要通过旋转来保持平衡,而旋转是非常耗时的,由此我们可以知道AVL树适合用于插入删除次数比较少,但查找多的情况。
从上面这张图我们可以看出,任意节点的左右子树的平衡因子差值都不会大于1.
局限性
由于维护这种高度平衡所付出的代价比从中获得的效率收益还大,故而实际的应用不多,更多的地方是用追求局部而不是非常严格整体平衡的红黑树.当然,如果应用场景中对插入删除不频繁,只是对查找要求较高,那么AVL还是较优于红黑树.
应用
Windows NT内核中广泛存在.
红黑树
简介
一种二叉查找树,但在每个节点增加一个存储位表示节点的颜色,可以是red或black. 通过对任何一条从根到叶子的路径上各个节点着色的方式的限制,红黑树确保没有一条路径会比其它路径长出两倍.它是一种弱平衡二叉树(由于是若平衡,可以推出,相同的节点情况下,AVL树的高度低于红黑树),相对于要求严格的AVL树来说,它的旋转次数变少,所以对于搜索,插入,删除操作多的情况下,我们就用红黑树.
性质
每个节点非红即黑.
根节点是黑的。
每个叶节点(叶节点即树尾端NUL指针或NULL节点)都是黑的.
如果一个节点是红的,那么它的两儿子都是黑的.
对于任意节点而言,其到叶子点树NIL指针的每条路径都包含相同数目的黑节点.
应用
- 广泛用于C++的STL中,map和set都是用红黑树实现的
- 著名的linux进程调度Completely Fair Scheduler,用红黑树管理进程控制块,进程的虚拟内存区域都存储在一颗红黑树上,每个虚拟地址区域都对应红黑树的一个节点,左指针指向相邻的地址虚拟存储区域,右指针指向相邻的高地址虚拟地址空间.
- IO多路复用epoll的实现采用红黑树组织管理sockfd,以支持快速的增删改查.
- ngnix中,用红黑树管理timer,因为红黑树是有序的,可以很快的得到距离当前最小的定时器.
B树和B+树
mysql索引底层存储机制是使用B+树进行实现;B+树数据结构是B-树实现的增强版本。尽管B+树支持B-树索引的所有特性,它们之间最显著的不同点在于B+树中底层数据是根据被提及的索引列进行排序的。B+树还通过叶子节点之间的附加引用来优化扫描性能。
B树(m=4)结构图如下:
B+树结构如下:
B+搜索和B-搜索不同,区别是B+树只有达到叶子节点才命中(B-树可以在非叶子节点命中),其性能等价于关键字全集做一次二分搜索。
B/B+性能分析:
(1) : n个节点的平衡二叉树的告诉为H(即logn),而n个节点的B/B+树的高度为
(1) : nGE个节点的平衡二叉树的告诉为H(即logn),而n个节点的B/B+树的高度为logt((n+1)/2)+1;
(2)若要作为内存中的查找表,B树却不一定比平衡二叉树好,尤其当m较大时更是如此.因为查找操作CPU的时间在B-树上是O(mlogtn)=O(lgn(m/lgt)),而m/lgt>1;所以m较大时O(mlogtn)比平衡二叉树的操作时间大得多. 因此在内存中使用B树必须取较小的m.(通常取最小值m=3,此时B-树中每个内部结点可以有2或3个孩子,这种3阶的B-树称为2-3树)。
B+树的特性:
(1)所有关键字都出现在叶子节点的链表中,叶子节点相当于存储数据的数据层。
(2)不可能在非叶子节点上命中。
(3)非叶子节点相当于是叶子节点的索引,叶子节点相当于数据层。
4. 版本变迁及特性
有时面试过程中会谈到mysql版本特性问题,此时如果我们队mysql版本变迁有比较深入的了解便比较容易给面试官留下好的印象记忆点,也代表着我们自身关注着行业相关技术的最新发展,不与时代脱节。
目前市场上mysql存在的版本基本是5.6,5.7,8.0三个大版本。5.6稳定版本在13年发布,5.7版本15年发布,8.0稳定版本18年初;我们需要了解5.7版本相对于5.6版本、8.0相对于5.7版本有哪些重要特性变化;
Mysql5.7新变化特性有:
a. 灵活性上开始支持json串格式字段;mysql对json的支持是在server层;server层提供了一堆便于操作JSON的函数,至于存储,就是简单地将JSON编码成BLOB,然后交由存储引擎层进行处理,也就是说,MySQL 5.7的JSON支持与存储引擎没有关系,MyISAM 存储引擎也支持JSON 格式;mysql的json格式可以混合存储结构化数据和非结构化数据,同时拥有关系型数据库和非关系型数据库的优点;
b. generated column. 即数据库中的这一列由其他列计算而得。例如,知道直角三角形的两条直角边,要求直角三角形的面积。很明显,面积可以通过两条直角边计算而得,那么,这时候就可以在数据库中只存放直角边,面积使用generated column.
CREATE TABLE triangle (sidea DOUBLE, sideb DOUBLE, area DOUBLE AS (sidea * sideb / 2);
insert into triangle(sidea, sideb) values(3, 4);
在这个例子中,如果我们需要根据面积创建索引以加快查询,就无法在用户代码里面实现,使用generate column就变得非常简单:
alter table triangle add index ix_area(area);
c. 性能提升。
Mysql8.0新版本特性如下:
a. mysql8开始支持文档存储。开发人员可以将无模式 JSON 文档集合与关系表放在一起使用(文档是一堆键值对的集合,表现为 JSON 结构)
b. 性能大幅提升。速度比5.7快两倍,在读写工作负载、IO密集型工作负载、高竞争工作负载;
c. 默认字符编码改为了utf8mb4.
5. 事务隔离
任何支持事务的数据库必须满足四个特性:原子性(atomicity), 一致性(consistency),隔离性(isolation)、持久性(durability)
⑴ 原子性(Atomicity)
原子性是指事务包含的所有操作要么全部成功,要么全部失败回滚,这和前面两篇博客介绍事务的功能是一样的概念,因此事务的操作如果成功就必须要完全应用到数据库,如果操作失败则不能对数据库有任何影响。
⑵ 一致性(Consistency)
一致性是指事务必须使数据库从一个一致性状态变换到另一个一致性状态,也就是说一个事务执行之前和执行之后都必须处于一致性状态。
拿转账来说,假设用户A和用户B两者的钱加起来一共是5000,那么不管A和B之间如何转账,转几次账,事务结束后两个用户的钱相加起来应该还得是5000,这就是事务的一致性。
⑶ 隔离性(Isolation)
隔离性是当多个用户并发访问数据库时,比如操作同一张表时,数据库为每一个用户开启的事务,不能被其他事务的操作所干扰,多个并发事务之间要相互隔离。
即要达到这么一种效果:对于任意两个并发的事务T1和T2,在事务T1看来,T2要么在T1开始之前就已经结束,要么在T1结束之后才开始,这样每个事务都感觉不到有其他事务在并发地执行。
关于事务的隔离性数据库提供了多种隔离级别,稍后会介绍到。
⑷ 持久性(Durability)
持久性是指一个事务一旦被提交了,那么对数据库中的数据的改变就是永久性的,即便是在数据库系统遇到故障的情况下也不会丢失提交事务的操作。
事务隔离相关的几个问题如下:
a. 脏读
脏读是指在一个事务处理过程里读取了另一个未提交的事务中的数据。
当一个事务正在多次修改某个数据,而在这个事务中这多次的修改都还未提交,这时一个并发的事务来访问该数据,就会造成两个事务得到的数据不一致。例如:用户A向用户B转账100元,对应SQL命令如下
update account set money=money+100 where name=’B’; (此时A通知B)
update account set money=money - 100 where name=’A’;
当只执行第一条SQL时,A通知B查看账户,B发现确实钱已到账(此时即发生了脏读),而之后无论第二条SQL是否执行,只要该事务不提交,则所有操作都将回滚,那么当B以后再次查看账户时就会发现钱其实并没有转。
b. 不可重复读
不可重复读是指在对于数据库中的某个数据,一个事务范围内多次查询却返回了不同的数据值,这是由于在查询间隔,被另一个事务修改并提交了。
例如事务T1在读取某一数据,而事务T2立马修改了这个数据并且提交事务给数据库,事务T1再次读取该数据就得到了不同的结果,发送了不可重复读。
不可重复读和脏读的区别是,脏读是某一事务读取了另一个事务未提交的脏数据,而不可重复读则是读取了前一事务提交的数据。
在某些情况下,不可重复读并不是问题,比如我们多次查询某个数据当然以最后查询得到的结果为主。但在另一些情况下就有可能发生问题,例如对于同一个数据A和B依次查询就可能不同,A和B就可能打起来了……
c. 虚读(幻读)
幻读是事务非独立执行时发生的一种现象。例如事务T1对一个表中所有的行的某个数据项做了从“1”修改为“2”的操作,这时事务T2又对这个表中插入了一行数据项,而这个数据项的数值还是为“1”并且提交给数据库。而操作事务T1的用户如果再查看刚刚修改的数据,会发现还有一行没有修改,其实这行是从事务T2中添加的,就好像产生幻觉一样,这就是发生了幻读。
幻读和不可重复读都是读取了另一条已经提交的事务(这点就脏读不同),所不同的是不可重复读查询的都是同一个数据项,而幻读针对的是一批数据整体(比如数据的个数)。
现在来看看MySQL数据库为我们提供的四种隔离级别:
① Serializable (串行化):可避免脏读、不可重复读、幻读的发生。
② Repeatable read (可重复读):可避免脏读、不可重复读的发生。
③ Read committed (读已提交):可避免脏读的发生。
④ Read uncommitted (读未提交):最低级别,任何情况都无法保证
以上四种隔离级别最高的是Serializable级别,最低的是Read uncommitted级别,当然级别越高,执行效率就越低。像Serializable这样的级别,就是以锁表的方式(类似于Java多线程中的锁)使得其他的线程只能在锁外等待,所以平时选用何种隔离级别应该根据实际情况。在MySQL数据库中默认的隔离级别为Repeatable read (可重复读)
6.MVCC
基本原理
MVCC的实现,通过保存数据在某个时间点的快照来实现的。这意味着一个事务无论运行多长时间,在同一个事务里能够看到数据一致的视图。根据事务开始的时间不同,同时也意味着在同一个时刻不同事务看到的相同表里的数据可能是不同的。
基本特征
- 每行数据都存在一个版本,每次数据更新时都更新该版本。
- 修改时Copy出当前版本随意修改,各个事务之间无干扰。
- 保存时比较版本号,如果成功(commit),则覆盖原记录;失败则放弃copy(rollback)
InnoDB存储引擎中MVCC的实现策略:
在每一行数据中额外保存两个隐藏的列:当前行创建时的版本号和删除时的版本号(可能为空,其实还有一列称为回滚指针,用于事务回滚,不在本文范畴)。这里的版本号并不是实际的时间值,而是系统版本号。每开始新的事务,系统版本号都会自动递增。事务开始时刻的系统版本号会作为事务的版本号,用来和查询每行记录的版本号进行比较。
每个事务又有自己的版本号,这样事务内执行CRUD操作时,就通过版本号的比较来达到数据版本控制的目的。
补充:
1). MVCC手段只适用于Msyql隔离级别中的读已提交(Read committed)和可重复读(Repeatable Read).
2). Read uncimmitted由于存在脏读,即能读到未提交事务的数据行,所以不适用MVCC.
原因是MVCC的创建版本和删除版本只要在事务提交后才会产生。
3). 串行化由于是会对所涉及到的表加锁,并非行锁,自然也就不存在行的版本控制问题。
4). 通过以上总结,可知,MVCC主要作用于事务性的,有行锁控制的数据库模型。
关于Mysql中MVCC的总结
客观上,我们认为他就是乐观锁的一整实现方式,就是每行都有版本号,保存时根据版本号决定是否成功。
但由于Mysql的写操作会加排他锁(前文有讲),如果锁定了还算不算是MVCC?
了解乐观锁的小伙伴们,都知道其主要依靠版本控制,即消除锁定,二者相互矛盾,so从某种意义上来说,Mysql的MVCC并非真正的MVCC,他只是借用MVCC的名号实现了读的非阻塞而已。
7.NoSQL 和关系数据库的区别?(2018-4-16-lxy)
a. SQL 数据存在特定结构的表中;而NoSQL 则更加灵活和可扩展,存储方式可以省是JSON 文档、
哈希表或者其他方式。
b. 在SQL 中,必须定义好表和字段结构后才能添加数据,例如定义表的主键(primary key),索引
(index),触发器(trigger),存储过程(stored procedure)等。表结构可以在被定义之后更新,但是如果有
比较大的结构变更的话就会变得比较复杂。在NoSQL 中,数据可以在任何时候任何地方添加,不需要
先定义表。
c. SQL 中如果需要增加外部关联数据的话,规范化做法是在原表中增加一个外键,关联外部数据表。
而在NoSQL 中除了这种规范化的外部数据表做法以外,我们还能用如下的非规范化方式把外部数据直
接放到原数据集中,以提高查询效率。缺点也比较明显,更新审核人数据的时候将会比较麻烦。
d. SQL 中可以使用JOIN 表链接方式将多个关系数据表中的数据用一条简单的查询语句查询出来。
NoSQL 暂未提供类似JOIN 的查询方式对多个数据集中的数据做查询。所以大部分NoSQL 使用非规范
化的数据存储方式存储数据。
e. SQL 中不允许删除已经被使用的外部数据,而NoSQL 中则没有这种强耦合的概念,可以随时删
除任何数据。
f. SQL 中如果多张表数据需要同批次被更新,即如果其中一张表更新失败的话其他表也不能更新成
功。这种场景可以通过事务来控制,可以在所有命令完成后再统一提交事务。而NoSQL 中没有事务这
个概念,每一个数据集的操作都是原子级的。
g. 在相同水平的系统设计的前提下,因为NoSQL 中省略了JOIN 查询的消耗,故理论上性能上是
优于SQL 的。
8.Mysql 数据库中怎么实现分页?(2018-4-23-zcz)
select * from table limit (start-1)*limit,limit; 其中start 是页码,limit 是每页显示的条数。
9.sql 语句怎么看效率?(2018-4-23-zcz)
SQLServer2005-->新建一个查询-->输入语句SELECT * FROM Person.Contact
执行(F5)-->Ctrl+L。
10.虽然UPDATE、DELETE 语句的写法基本固定,但是还是对UPDATE 语句给点建议:
a) 尽量不要修改主键字段。
b) 当修改VARCHAR 型字段时,尽量使用相同长度内容的值代替。
c) 尽量最小化对于含有UPDATE 触发器的表的UPDATE 操作。
d) 避免UPDATE 将要复制到其他数据库的列。
e) 避免UPDATE 建有很多索引的列。
f) 避免UPDATE 在WHERE 子句条件中的列。
11.数据库的设计?(2018-5-1-lxy)
第一范式:数据库表的每一列都是不可分割的原子数据项,即列不可拆分。
第二范式:建立在第一范式的基础上,要求数据库表中的每个实例或记录必须是可以唯一被区分的,
即唯一标识。
第三范式:建立在第二范式的基础上,任何非主属性不依赖与其他非主属性,即引用主键。
12.存储过程和函数的区别?(2018-5-1-lxy)
相同点:存储过程和函数都是为了可重复的执行操作数据库的sql 语句的集合。
1)存储过程和函数都是一次编译,就会被缓存起来,下次使用就直接命中已经编译好的sql 语句,
不需要重复使用。减少网络交互,减少网络访问流量。
不同点:标识符不同,函数的标识符是function,存储过程是proceduce。
1)函数中有返回值,且必须有返回值,而过程没有返回值,但是可以通过设置参数类型(in,out)
来实现多个参数或者返回值。
2)存储函数使用select 调用,存储过程需要使用call 调用。
3)select 语句可以在存储过程中调用,但是除了select..into 之外的select 语句都不能在函数中使
用。
4)通过in out 参数,过程相关函数更加灵活,可以返回多个结果。
14.Mysql 日志(2018-5-1-lyf)
错误日志:记录启动,运行或者停止mysql 时出现的问题;
通用日志:记录建立的客户端连接和执行的语句;
二进制日志:记录所有更改数据的语句;
慢查询日志:记录所有执行时间超过long_query_time 秒的查询或者不适用索引的查询)
通过使用--slow_query_log[={0|1}]选项来启用慢查询日志,所有执行时间超多long_query_time 的语
句都会被记录。
面试题一:知道mysql的事务隔离吗?/事务隔离分哪几个级别?/事务隔离性怎么保证/...**
回答思路:
空间线:
事务ACID概念
事务隔离四个级别(概念及优缺点)
MySQL事务隔离性和其他DB区别
思路串联:事务ACID-> 事务隔离四个级别 ->留MVCC/GAP问题引子
示例答案:
数据库支持事务本身需要有具备四个特性:原子性、一致性、隔离性和持久性,也即ACID。其中事务的隔离性简单来说就是并发执行的多个事务之间互不干扰。
事务隔离总体分为四个级别:第一个是RU(未提交读),该级别事务内容易出现脏读的情况,即事务A读到了事务B没有提交的数据;为了解决脏读问题,可以提高事务隔离级别到RC(提交读),此时事务A不会读到其他事务未提交的数据,但又产生了一个新的现象:事务A执行的过程中,有可能另外一个事务B提交了数据,此时事务读取的数据和之前不一致,即出现了不可重复读的问题;所以mysql的InnoDB本身默认采用了第三个事务隔离级别RR(可重复读),该级别使用MVCC(多版本并发控制)解决重复读的问题,一般的RR级别会出现幻读的问题,及同一个事务多次执行同一个select,读取到的数据行发生了改变,这是因为数据行发生了行数减少或者新增;而最高的事务隔离级别是SE(可序列化),该方式下事务相当于串行执行,解决了脏读、不可重复读、幻读等问题,但对性能和效率的影响很大,生产环境中很少会使用该隔离级别;
具体到mysql中,mysql默认的RR级别有一些特别,因为其引入了GAP LOCK(间隙锁)的概念,可在RR级别即可解决幻读的问题;另外一个特性是mysql里的MVCC只解决读-写的阻塞问题,写-写依然还是阻塞的。
GAPLOCK会锁住某一段范围中的记录;
15. Mysql和MongoDB的区别
MySQL是关系型数据库的一种,其存储引擎有MyISam, InnoDB,Merge等,目前在业界中大多使用的支持事务InnoDB存储引擎,从15年MySQL5.7开始,MySQL开始支持json格式(开始向nosql数据库靠近);而MongoDB去年8月份发布的最新版本4.0开始支持多文档事务,当前其默认的存储引擎wiredtiger性能非常卓越;
mysql和MongoDB数据库发展越来越类似,都在取其精华,在具体的数据库选型时,两种DB底层的实现机制可能是一大考虑因素。mysql索引底层是用B+树实现的,而MongoDB则是采取的B树,B树的结构也就决定了MongoDB在海量读写的情况下性能比mysql卓越(时间复杂度是O(1)-O(logN)), 而MySQL B+树的特性也决定了MySQL更适合多区间范围查询的业务需求。
当然,在具体的项目DB选择过程中,我们还需要考虑到成本、团队成员的意愿、技术栈等情况。总的来说,在当前的情况下,如果是海量数据高并发读写,从技术的角度推荐使用MongoDB,如果数据结构相对统一,同时对于事务有较高要求,个人倾向于MySQL。
三、MongoDB
1. 存储引擎
MMAP:
MongoDB MMAPv1 引擎的扩展规则是,每次存储文件容量翻倍,直至增加到 2G 大小
缺点:
1) 库级锁,在3.0版本时有提升到collection锁,但粒度仍然很大;
2) 删除元素时存储空间未真正释放;
Wiredtiger:
2015年3.0版本发布后,引入wiredtiger存储引擎,3.2版本默认存储引擎都改为了wiredtiger,
特点:
a. 文档级别锁,解决了锁粒度过大的问题;
b. 磁盘数据压缩,支持对所有集合和索引进行Block压缩和前缀压缩(如果数据库启用了journal,journal文件一样会压缩),已支持的压 缩选项包括:不压缩、Snappy压缩和Zlib压缩。
c. 删除数据时,数据会立即删除;
d. MongoDB3.0在多线程、批量插入场景下较之于MongoDB2.6有大约4-7倍的增长
Rocksdb
RocksDB 是基于 LSM tree 结构组织数据,其针对写入做了优化,将随机写入转换成了顺序写入,能保证持续高效的数据写入。
写场景较多时刚开始 Wiredtiger 的写入性能远超 RocksDB,而随着数据量越来越大,WT的写入能力开始下降,而 RocksDB 的写入一直比较稳定。
2.版本变迁及特性
MongoDB历史变化中,有两个大的版本变化节点,分别是:
a. MongoDB 3.0版本可能是MongoDB诞生以来最重要的一个版本,该版本引入了插件式的存储引擎架构,允许第三方根据实际项目的需要开发存储引擎,类似于MySql中的分层存储引擎架构。随同这种架构发布的新的存储引擎为WiredTiger,在随后的3.2版本中,默认的存储引擎改为了wiredtiger。
b. MongoDB 4.0版本添加了一个极为重要的功能:多文档事务支持,支持复制集内部跨一或多个集合的多文档事务,保证针对多个文档的更新的原子性。而在未来的MongoDB 4.2 版本,还会支持分片集群的分布式事务。
3. 底层存储机制(B树)
MongoDB的索引底层存储采用的是B-tree进行存储,为什么MongoDB底层使用B-TREE而MySQL使用B+tree呢?
空间局部性原理:如果一个存储器的某个位置被访问,那么将它附近的位置也会被访问
传统用来搜索的平衡二叉树有很多,如 AVL 树,红黑树等。这些树在一般情况下查询性能非常好,但当数据非常大的时候它们就无能为力了。原因当数据量非常大时,内存不够用,大部分数据只能存放在磁盘上,只有需要的数据才加载到内存中。一般而言内存访问的时间约为 50 ns,而磁盘在 10 ms 左右。速度相差了近 5 个数量级,磁盘读取时间远远超过了数据在内存中比较的时间。这说明程序大部分时间会阻塞在磁盘 IO 上。
为什么 MongoDB 使用B-树:
MongoDB 是一种 nosql,也存储在磁盘上,被设计用在 数据模型简单,性能要求高的场合。性能要求高,看看B/B+树的区别第一点:
B+树内节点不存储数据,所有 data 存储在叶节点导致查询时间复杂度固定为 log n。而B-树查询时间复杂度不固定,与 key 在树中的位置有关,最好为O(1)
我们说过,尽可能少的磁盘 IO 是提高性能的有效手段。MongoDB 是聚合型数据库,而 B-树恰好 key 和 data 域聚合在一起。
为什么 Mysql 使用B+树:
Mysql 是一种关系型数据库,区间访问是常见的一种情况,而 B-树并不支持区间访问(可参见上图),而B+树由于数据全部存储在叶子节点,并且通过指针串在一起,这样就很容易的进行区间遍历甚至全部遍历。见B/B+树的区别第二点:
B+树叶节点两两相连可大大增加区间访问性,可使用在范围查询等,而B-树每个节点 key 和 data 在一起,则无法区间查找。
其次B+树的查询效率更加稳定,数据全部存储在叶子节点,查询时间复杂度固定为 O(log n)。
最后第三点:
B+树更适合外部存储。由于内节点无 data 域,每个节点能索引的范围更大更精确。
4. 和关系型数据库MySQL对比
随着数据库本身的飞速发展,MySQL和MongoDB作为关系型数据库和非关系型数据中的一种常见数据库,他们之间表现出来的特性越来越类似,已经很难去通过是否支持事务、性能等方面的过往的评判标准来定位选型。
大体上一般如果数据量规模不是特别大,同时关系性结构比较多,应用场景事务要求较多,此时mysql可能较为适用;如果是海量数据存储,读取和写入频率极高,则推荐适用MongoDB等nosql数据库。
当然在实际的企业项目开发过程中,DB的选型情况远比上面复杂;除了业务场景的特性,还需要考虑到成本(运维成本、学习成本)、成员意愿、公司技术栈等情况;
5. 集群及扩展
当数据量规模达到亿级以上时,单一的collection已经很难独自承担整体的存取需求,此时便需要进行db扩展,常用的数据扩展方法有:
a. 水平扩展:分库,分collection
b. 垂直扩展:分片
四、Redis相关
1. 用途及使用场景
Redis是一个开源的key-value数据库,支持string、list、set、zset和hash类型数据。其存储介质是内存。在实际的企业开发中,一般在以下几类场景中会用到:
a. 缓存高频次访问的数据,降低数据库io
b. 分布式架构,做session共享
c. 利用zset类型可以存储排行榜
d. 利用list做简易MQ或存储最新的n个数据
2. redis底层存储机制(ziplist, skiplist)
redis常规键的底层实现如下:
list键:双向链表
hash键:字典dict
zset键:跳跃表zskiplist
但是当list键里包含的元素较少、并且每个元素要么是小整数要么是长度较小的字符串时,redis将会用ziplist作为list键的底层实现。同理hash和zset在这种场景下也会使用ziplist。
既然已有底层结构可以实现list、hash、zset键,为什么还要用ziplist呢?
当然是为了节省内存空间,由于时间原因此处暂不深入ziplist的内部实现;
3. redis集群
redis的集群化方案 目前有三种
(1)Twitter开发的twemproxy
(2)豌豆荚开发的codis
(3)redis官方的redis-cluster
相较而言,当前redis-cluster功能更为强大;
4. bloom算法
redis本身是基于内存的nosql数据库,在实际开发过程中,随着业务的扩展,需要redis进行缓存的数据可能越来越庞大,使用redis,memcache等内存数据库进行缓存时,需要的内存空间可能需要几十个G甚至几百G的内存,对于大多数中小型公司而言,这是一笔巨大的成本,比如垃圾邮箱地址数目达到十亿数量级时,传统方式存储需要的内存可能需要几十个G,此时便可以引入bloom算法,采用基于bloom算法的开源数据库;
那么何为bloom算法呢?
Bloom Filter算法就是对于有n个元素的集合S={x1, x2,……,xn},我们用k个哈希函数(h1,h2,……,hn),分别将S中的每一个元素映射到一个m位的位数组(bm-1bm-2……b1b0)中。该位数组在初始化时所有置为0,每当用哈希函数映射到该位时则将该位置为1。对于已经置为1的位则不在反复置1。
比如。将S={x1,x2,x3}这个集合用3个哈希函数映射到一个14位的位数组中,如图所看到的:
使用Bloom Filter我们能够推断一个元素是否在某一个集合中。假设这个集合是使用线性结构存储的话。其查找的时间复杂度是O(n);使用像二叉树或B-tree这种树形结构存储的话其查找的时间复杂度是O(logn)。而使用Bloom Filter在能够容忍一定错误率的情况下,其时间复杂度是O(1)。因此,与传统的权衡空间或时间的算法不同,Bloom Filter 极其巧妙。通过引入一定的错误率来换取时间和空间,在某些应用大大提高了性能。
五、列式数据库
列式数据库我简单的和大家过一遍基础知识。
怎么来理解或区分数据库和数据仓库的关系
业界经常说的术语是OLTP,这是on-line transaction processing的简写。联机事务处理。
OLAP是On-Line Analytical Processing 翻译成联机分析处理。 从名字来看,可以看出一个侧重事务处理。一个侧重分析处理。事务处理,就是交易数据。如订单、商品等数据的增删查改。分析处理,要对这些数据分析出统计结果。分析处理,就要使用数据仓库来存储数据了,要与业务数据库分开,而数据来自于业务数据库。
联机事务处理使用的是交易型数据库,即行式存储关系型数据库如oracle、sqlserver、mysql。
联机分析处理使用的是分析型数据库,即列式关系型数据库hbase、hive、clickhouse等。
数据仓库只是一个概念,至于用什么数据库,随自己。对数据的分析处理,得到统计结果,归到数据仓库里面去,以提供在线查询
为什么数据仓库喜欢使用列式关系型储数据库?
数据仓库使用的技术方案,有很多种。可以使用关系型数据库mysql,目前,业界一般使用列存储。
为什么不用mysql等行存储关系数据库来做数据仓库? 而一般使用列存储数据库, 是考虑到数据仓库的以下特点:
1)、数据仓库的数据来源多个系统。可能是文件、可能是其他关系型数据库中的交易数据。
2)、需要多个维度建立数据统计模型。
3)、存储数据量。历史的,存档的,归纳的,计算的数据。
4)、需要访问大量的记录才能统计出结果。如果统计性能上不能很慢,无法出统计结果。就满足不了分析统计的需求。涉及到复杂的聚合统计查询,这类系统就比较难以处理了,比如要查询某一些类型的用户过去三个月购买最多的商品,因为同一时间需要查询大量数据,OLTP(关系数据库) 系统并不擅长处理这类需求。
5)、更新数据很少。都是添加数据、查询数据。于是对查询速度要求高。
列式型关系数据库,使用上与mysql一样,都是sql语句操作,也是关系表设计。唯独底层存储原理不一样。下面解释。
对比行存储和列存储
下面来看网上找的一张图,对比行存储和列存储
行存储的一行数据(此行的所有数据)都在一起,紧接着就是第二行数据,依次下去。
列存储不同的是,一列的所有数据都放在一起了。
作业1 为什么用Mysql?/Mysql和MongoDB差别在哪?/mysql索引这块了解吗/...
作业2 什么时候 使用Redis?/ 你们之前Redis使用多吗?/...