Pentium.Labs

System全家桶:https://zhuanlan.zhihu.com/c_1238468913098731520

导航

数据库知识点总结1

当年肥工的DB课讲的其实还挺好的...就用当时的笔记叭

(所以当年为什么不整理呢?还是懒叭

 

关系数据库的一些概念

完整性防止DB中存在不符合规定的数据(eg:性别只能是男或女)

实体完整性:primary key中的属性取值必须唯一且不能为空

参照完整性:若F是R的外码(foreign key),K是S的主码(primary key),F连接K。那么对于R中的每个元祖,R.F必须是 在S.K中出现过的值 或者 NULL

用户定义的完整性:用户自己在具体的DB中指定的约束(定义:NOT NULL / UNIQUE / CHECK)

触发器:用于实现用户定义的完整性        CREATE TRIGGER ON ... AFTER ...

存储过程用SQL语句实现一些用户定义的业务逻辑

关系模型

(略)

 

SQL

(略)

 

索引

B+Tree

B Tree 指的是 Balance Tree,也就是平衡树。平衡树是一颗查找树,并且所有叶子节点位于同一层。

B+ Tree 是基于 B Tree 和叶子节点顺序访问指针进行实现,它具有 B Tree 的平衡性,并且通过顺序访问指针来提高区间查询的性能。

在 B+ Tree 中,一个节点中的 key 从左到右非递减排列,如果某个指针的左右相邻 key 分别是 keyi 和 keyi+1,且不为 null,则该指针指向节点的所有 key 大于等于 keyi 且小于等于 keyi+1

进行查找操作时,首先在根节点进行二分查找,找到一个 key 所在的指针,然后递归地在指针所指向的节点进行查找。直到查找到叶子节点,然后在叶子节点上进行二分查找,找出 key 所对应的 data。

插入删除操作会破坏平衡树的平衡性,因此在插入删除操作之后,需要对树进行一个分裂、合并、旋转等操作来维护平衡性。

与红黑树的比较

红黑树等平衡树也可以用来实现索引,但是文件系统及数据库系统普遍采用 B+ Tree 作为索引结构,主要有以下两个原因:

(一)更少的查找次数

平衡树查找操作的时间复杂度和树高 h 相关,O(h)=O(logdN),其中 d 为每个节点的出度。

红黑树的出度为 2,而 B+ Tree 的出度一般都非常大,所以红黑树的树高 h 很明显比 B+ Tree 大非常多,查找的次数也就更多。

(二)利用磁盘预读特性

为了减少磁盘 I/O 操作,磁盘往往不是严格按需读取,而是每次都会预读。预读过程中,磁盘进行顺序读取,顺序读取不需要进行磁盘寻道,并且只需要很短的磁盘旋转时间,速度会非常快。

操作系统一般将内存和磁盘分割成固定大小的块,每一块称为一页,内存与磁盘以页为单位交换数据。数据库系统将索引的一个节点的大小设置为页的大小,使得一次 I/O 就能完全载入一个节点。并且可以利用预读特性,相邻的节点也能够被预先载入。

B+ Tree、LSM Tree:https://www.cnblogs.com/pdev/p/11277784.html

MYSQL:http://blog.codinglabs.org/articles/theory-of-mysql-index.html

Hash:https://www.cnblogs.com/pdev/p/11332264.html

红黑树:https://www.jianshu.com/p/e136ec79235c

索引的优点

  • 大大减少了服务器需要扫描的数据行数。
  • 帮助服务器避免进行排序和分组,以及避免创建临时表(B+Tree 索引是有序的,可以用于 ORDER BY 和 GROUP BY 操作。临时表主要是在排序和分组过程中创建,不需要排序和分组,也就不需要创建临时表)。
  • 将随机 I/O 变为顺序 I/O(B+Tree 索引是有序的,会将相邻的数据都存储在一起)。

索引的使用条件

  • 对于非常小的表、大部分情况下简单的全表扫描比建立索引更高效;
  • 对于中到大型的表,索引就非常有效;
  • 但是对于特大型的表,建立和维护索引的代价将会随之增长。这种情况下,需要用到一种技术可以直接区分出需要查询的一组数据,而不是一条记录一条记录地匹配,例如可以使用分区技术。

 

事务

我们在写Java程序,遇到并发问题时,会想到用锁来解决。数据库遇到并发问题怎么解决呢?答案就是事务,事务的本质就是锁和并发的结合体(可以理解成在数据库系统上执行的一个函数。比如在银行数据库中,把A的100元钱转给B)

事务指的是满足 ACID 特性的一组操作,可以通过 Commit 提交一个事务,也可以使用 Rollback 进行回滚。一个事务包含了多个命令,服务器在执行事务期间,不会改去执行其它客户端的命令请求。事务是并发控制的基本单位

事务中的多个命令被一次性发送给服务器,而不是一条一条发送,这种方式被称为流水线,它可以减少客户端与服务器之间的网络通信次数从而提升性能。

ACID特性

  • Atomicity    事务被视为不可分割的最小单元,事务的所有操作要么全部提交成功,要么全部失败回滚。回滚可以用回滚日志来实现,回滚日志记录着事务所执行的修改操作,在回滚时反向执行这些修改操作即可。
  • Consistency    数据库在事务执行前后都保持一致性状态。在一致性状态下,所有事务对一个数据的读取结果都是相同的。
  • Isolation    一个事务所做的修改在最终提交以前,对其它事务是不可见的。换句话说就是并发执行的事务不会相互影响,其对数据库的影响和它们串行执行时一样。
  • Durability    一旦事务提交,则其所做的修改将会永远保存到数据库中。即使系统发生崩溃,事务执行的结果也不能丢失。使用重做日志来保证持久性。
  • 只有满足一致性,事务的执行结果才是正确的。
  • 在无并发的情况下,事务串行执行,隔离性一定能够满足。此时只要能满足原子性,就一定能满足一致性。
  • 在并发的情况下,多个事务并行执行,事务不仅要满足原子性,还需要满足隔离性,才能满足一致性。
  • 事务满足持久化是为了能应对数据库崩溃的情况。
  • 并发控制技术保证了事务的隔离性,使数据库的一致性状态不会因为并发执行的操作被破坏。
  • 日志恢复技术保证了事务的原子性,使一致性状态不会因事务或系统故障被破坏。同时使已提交的对数据库的修改不会因系统崩溃而丢失,保证了事务的持久性。

恢复

 

并发控制

事务是并发控制的基本单位。

并发一致性问题

在并发环境下,事务的隔离性很难保证,因此会出现很多并发一致性问题。解决方法是通过并发控制来保证隔离性。并发控制可以通过封锁来实现,但是封锁操作需要用户自己控制,相当复杂。数据库管理系统提供了事务的隔离级别,让用户以一种更轻松的方式处理并发一致性问题。

并发控制主要技术:封锁、时间戳、乐观控制法、多版本并发控制等。

封锁:相当于分布式中的加锁/解锁。基本封锁类型:排他锁(X 锁 / 写锁)、共享锁(S 锁 / 读锁)。

  • 写锁:对A加写锁之后,其他事务不可再读写A
  • 读锁:对A加读锁之后,其他事务只能读A

封锁协议:规定加锁解锁的规则

两段锁协议:所有事务必须分两个阶段对数据项加锁/解锁:

  • 准备阶段:在对任何数据进行读、写操作之前,首先要申请并获得对该数据的封锁(此时可以申请任何锁,但不能释放锁)
    • 具体实现中,在准备阶段会有一个协调者,向参与者申请资源并锁定资源,执行事务操作。但是并没有commit或者rollback
  • 提交阶段:在释放一个封锁之后,事务不再申请和获得任何其他封锁(此时可以释放任何锁,但不能再申请锁)
    • 这一步才真正commit或者rollback。如果协调者发现所有参与者都返回yes就commit,只要有一个人返回no就rollback

若并发执行的所有事务都遵循两段锁协议,则对这些事务的任何并发调度策略都是可串行化的。

但是对于分布式事务,2pc有可能出现数据不一致的问题。如果要彻底解决这一问题就要用paxos或者Raft了。

封锁粒度:具体对哪个对象加锁

MySQL 中提供了两种封锁粒度:行级锁以及表级锁。
应该尽量只锁定需要修改的那部分数据,而不是所有的资源。锁定的数据量越少,发生锁争用的可能就越小,系统的并发程度就越高。
但是加锁需要消耗资源,锁的各种操作(包括获取锁、释放锁、以及检查锁状态)都会增加系统开销。因此封锁粒度越小,系统开销就越大。
在选择封锁粒度时,需要在锁开销和并发程度之间做一个权衡。

活锁:某个事务等待时间太长,可通过先来先服务的策略避免。

死锁:事务永远无法完成,同OS中的死锁

  • 预防:一次封锁法(每个事务必须一次将所有要使用的数据全部加锁)、顺序封锁法;
  • 诊断:超时法、等待图法;
  • 解除:撤销处理死锁代价最小的事务,并释放此事务的所有的锁,使其他事务得以继续运行下去。

可串行化调度:可串行性是并发事务正确调度的准则。表示并发调度的结果和完全串行执行的结果是一致的。

隔离级别事务具有隔离性,理论上来说事务之间的执行不应该相互产生影响,其对数据库的影响应该和它们串行执行时一样。然而完全的隔离性会导致系统并发性能很低,降低对资源的利用率,因而实际上对隔离性的要求会有所放宽,这也会一定程度造成对数据库一致性要求降低。事务的隔离级别越低,可能出现的并发异常越多,但是通常而言系统能提供的并发能力越强。

  • 未提交读(READ UNCOMMITTED):事务中的修改,即使没有提交,对其它事务也是可见的。        最低级别,任何情况都无法保证。
  • 提交读(READ COMMITTED):一个事务只能读取已经提交的事务所做的修改。换句话说,一个事务所做的修改在提交之前对其它事务是不可见的。       可避免脏读的发生
  • 可重复读(REPEATABLE READ):保证在同一个事务中多次读取同样数据的结果是一样的。       可避免脏读、不可重复读的发生。
  • 可串行化(SERIALIZABLE):强制事务串行执行。需要加锁实现,而其它隔离级别通常不需要。       可避免脏读、不可重复读、幻读的发生。

MVCC

在分布式数据库中,为了提高事务执行的并行度,会使用MVCC进行并发控制。MYSQL中就用MVCC进行并发控制

 

分布式数据库技术

切分

水平切分:水平切分又称为 Sharding,它是将同一个表中的记录拆分到多个结构相同的表中。
当一个表的数据不断增多时,Sharding 是必然的选择,它可以将数据分布到集群的不同节点上,从而缓存单个数据库的压力。

垂直切分:将一张表按列切分成多个表,通常是按照列的关系密集程度进行切分,也可以利用垂直切分将经常被使用的列和不经常被使用的列切分到不同的表中。
在数据库的层面使用垂直切分将按数据库中表的密集程度部署到不同的库中,例如将原来的电商数据库垂直切分成商品数据库、用户数据库等。

Sharding 策略
    哈希取模:hash(key) % N;
    范围:可以是 ID 范围也可以是时间范围;
    映射表:使用单独的一个数据库来存储映射关系。
Sharding 存在的问题
1. 事务问题    使用分布式事务来解决,比如 XA 接口。
2. 连接    可以将原来的连接分解成多个单表查询,然后在用户程序中进行连接。
3. ID 唯一性    使用全局唯一 ID(GUID)、为每个分片指定一个 ID 范围、分布式 ID 生成器 (如 Twitter 的 Snowflake 算法)

主从复制

主要涉及三个线程:binlog 线程、I/O 线程和 SQL 线程。

  • binlog 线程 :负责将主服务器上的数据更改写入二进制日志(Binary log)中。
  • I/O 线程 :负责从主服务器上读取二进制日志,并写入从服务器的中继日志(Relay log)。
  • SQL 线程 :负责读取中继日志,解析出主服务器已经执行的数据更改并在从服务器中重放(Replay)。

 

读写分离

主服务器处理写操作以及实时性要求比较高的读操作,而从服务器处理读操作。读写分离能提高性能的原因在于:

  • 主从服务器负责各自的读和写,极大程度缓解了锁的争用;
  • 从服务器可以使用 MyISAM,提升查询性能以及节约系统开销;
  • 增加冗余,提高可用性。

读写分离常用代理方式来实现,代理服务器接收应用层传来的读写请求,然后决定转发到哪个服务器。

 

 

 

 

 


 

https://github.com/CyC2018/CS-Notes/blob/master/notes/%E6%95%B0%E6%8D%AE%E5%BA%93%E7%B3%BB%E7%BB%9F%E5%8E%9F%E7%90%86.md

https://github.com/huihut/interview#-%E6%95%B0%E6%8D%AE%E5%BA%93

https://github.com/CyC2018/CS-Notes/blob/master/notes/MySQL.md

https://github.com/CyC2018/CS-Notes/blob/master/notes/Redis.md

 

posted on 2019-08-14 15:38  Pentium.Labs  阅读(475)  评论(0编辑  收藏  举报



Pentium.Lab Since 1998