无论是关系型数据库Mysql,Oracle,PostgreSQL,还是非关系型数据库HBase,MongoDB,Cassandra,都针对不同的应用场景解决不同的问题.
数据库的存储引擎是数据库的底层软件组织,数据库管理系统(DBMS)使用存储引擎创建,查询,更新和删除数据.不同的存储引擎提供不同的存储机制,索引技巧,锁定水平等功能,都有其特定的功能.现在,许多数据库管理系统都支持多种存储引擎,常用的存储引擎有MyISAM,InnoDB,Memory.
是Mysql默认的存储引擎,不支持数据库事务,行级锁和外键,因此在插入或更新数据即写操作时要锁定整 张表,效率较低.
MyISAM的特点是执行读取操作的速度快,且占用的内存和存储资源较少.它在设计之初就假设数据被组织成固定长度的记录,并且是按顺序存储的.在查找数据时,MyISAM直接查找文件的OFFSET,定位比InnoDB要快(InnoDB寻址要先映射到块,再映射到行)
InnoDB为MySQL提供了事务支持,回滚,崩溃修复能力,多版本并发控制,事务安全的操作.InnoDB的底层数据结构为B+树,B+树的每个结点都对应InnoDB的一个Page,Page的大小是固定的,一般被设为16KB.其中,非叶子结点只有键值,叶子结点包含完整的数据.如下图所示:
InnoDB使用于有以下需求的场景:
Memory表使用内存空间创建.每个Memory表实际上都对应一个磁盘文件用于持久化.Memory表因为数据是存放在内存当中的,因此访问速度非常快,通常使用Hash索引来实现数据索引.Memory表的缺点是一旦服务关闭,表中数据就会消失.
Memory还支持散列索引和B树索引.B树索引可以使用部分查询和通配查询,也可以使用不等于和大于等于等操作符方便批量数据访问,散列索引相对于B树索引基于Key的查询效率特别高,但是基于范围查询的查询效率不是很高.
创建索引是提高数据库查询的最常用办法,创建索引的原则:
范式是具有最小冗余的表结构
每列都是不可再分的最小数据单元,确保每列的原子性
第二范式在第一范式的基础上,规定表中非主键列不存在对主键的部分依赖,即每个表只描述一件事
满足第一范式和第二范式,并且表中的列不存在对非主键列的传递依赖,即表中的非主键列应与主键列紧密相关
ACID属性
存储过程指一组用于完成特定功能的SQL语句集,它被存储在数据库中,经过第一次编译后再次调用时不需再编译,用户通过指定存储过程的名字并给出参数来执行它.存储过程是数据库中的一个重要对象,可以通过存储过程快速完成复杂的计算操作.以下是常见的存储过程的优化思路:
触发器是一段能自动执行的程序,和普通存储过程的区别是"触发器在对某一个表或者数据操作时触发",例如进行update,insert,delete时,系统会自动调用和执行与表对应的触发器.触发器一般用于存储操作日志信息.
数据库的并发控制一般采用三种方法实现,分别是乐观锁,悲观锁及时间戳
乐观锁在读取数据时,认为别人不会去写所读的数据
悲观锁在修改数据时,不允许别人读取该数据,直到自己的整个事务都提交并释放锁,其他用户才能访问该数据.悲观锁又可分为排它锁(写锁)和共享锁(读锁).
指在数据库中额外添加一个时间戳列TimeStamp.每次读取数据时,都把时间戳也读取出来,在更新数据时把时间戳也加1,在提交之前跟数据库的该字段比较一次,如果比数据库大,则允许保存,否则不允许保存.这种处理方法不适用数据库提供的锁机制,数据库处理的并发量也大大提高.
在执行以下数据库操作时,数据库会自动应用行级锁
对当前操作的整张表加锁
最常使用的MyISAM与InnoDB都支持表级锁定,表级锁定分为共享锁和排它锁
表级锁的加锁速度快,但冲突多,行级锁的加锁速度慢,但冲突少,页级锁在两者之间做出了平衡,一次锁定相邻的一组记录
数据库锁是基于单个数据库实现的,在我们的业务跨多个数据库时,就要使用分布式锁来保证数据的一致性.下面介绍使用Redis实现一个分布式锁的流程.Redis实现的分布式锁以Redis setnx命令为中心实现,setnx是Redis的写入操作命令,具体语法为setnx(key val).在且仅在key不存在时,则插入一个key 为val的字符串,返回1;若key存在,则什么也不做,返回0.通过setnx实现分布式锁的思路如下.
数据库分表有垂直切分和水平切分两种
将表按照功能模块,关系密切程度划分到不同的数据库中.例如我们会创建数据库workDB,商品数据库payDB,用户数据库userDB,日志数据库logDB等分别用于存储各类表.如图所示:
在一个表中数据量过大时,我们可以把该表按照某种规则如userID散列进行划分,然后将其存储到多个结构相同的表和不同的库上.
在一个分布式系统中,一致性(Consistency),可用性(Availability)和分区容错性(Partition tolerance)三者不可兼得.
在分布式系统的所有数据备份中,在同一时刻是否有同样的值
在集群中一部分节点发生故障后,集群整体能否响应客户端的读写请求
系统不能在时限内达成数据的一致性,就意味着发生了分区,必须就当前操作在C和A之间做出选择,分区相当于对通信的时限要求.
分布式事务指设计多个数据库的事务,在分布式系统中,各个节点之间在物理上相互独立,通过网络进行沟通和协调.
二阶段提交指在计算机网络及数据库领域内,为了使分布式数据库的所有节点在进行数据提交时都保持一致性而设计的一种算法.在分布式系统中,每个节点只知道自己操作是否成功,却无法知道其他节点操作是否成功.
在一个事务跨越多个节点时,为了保证事务的ACID特性,需要引入一个作为协调者的组件来统一掌控所有节点(称作参与者)的操作结果.并最终指示这些节点是否真正提交操作结果(将更新后的数据写入磁盘),因此,二阶段提交的算法思路可以概括为:参与者将操作成败通知协调者,在由协调者根据所有参与者的反馈决定各参与者是提交操作还是中止操作.
事务协调者(事务管理器)给每个参与者(源管理器)都发送Prepare消息,参与者要么直接返回失败,要么在本地执行事务,写本地的redo和undo日志但不提交,是一种"万事俱备,只欠东风"的状态.
如果协调者接受到了参与者的失败消息或者超时,则直接给每个参与者都发送回滚消息,否则发送提交消息,如下如所示:
三阶段提交协议是两阶段提交的改进版本,具体改进如下: