如果要提供提交、回滚、崩溃恢复能力的事物安全(ACID兼容)能力,并要求实现并发控制,InnoDB是一个好的选择
如果数据表主要用来插入和查询记录,则MyISAM引擎能提供较高的处理效率
如果只是临时存放数据,数据量不大,并且不需要较高的数据安全性,可以选择将数据保存在内存中的Memory引擎,MySQL中使用该引擎作为临时表,存放查询的中间结果
如果只有INSERT和SELECT操作,可以选择Archive,Archive支持高并发的插入操作,但是本身不是事务安全的。Archive非常适合存储归档数据,如记录日志信息可以使用Archive
使用哪一种引擎需要灵活选择,一个数据库中多个表可以使用不同引擎以满足各种性能和实际需求,使用合适的存储引擎,将会提高整个数据库的性能
2、数据库索引类型及原理:B+树索引、哈希表索引
1.什么是索引
数据库索引好比是一本书前面的目录,能加快数据库的查询速度。
2.索引的优缺点
优点:
1.大大加快数据的检索速度
2.创建唯一性索引,保证数据库表中每一行数据的唯一性
3.加速表和表之间的连接
4.在使用分组和排序子句进行数据检索时,可以显著减少查询中分组和排序的时间
缺点
1.索引需要占用数据表以外的物理存储空间
2.创建索引和维护索引要花费一定的时间
3.当对表进行更新操作时,索引需要被重建,这样降低了数据的维护速度
3.索引类型
(1)唯一索引:UNIQUE
例如在学生表中给学号字段创建唯一索引:create unique index stusno on student(sno);
表明此索引的每一个索引值只对应唯一的数据记录,对于单列唯一性索引,这保证单列不包含重复的值。对于多了唯一性索引,保证多列值得组合不重复
(2)主键索引 primary key 即唯一+非空
数据库关系图中在给表定义主键将自动创建主键索引,该索引要求主键中的每个值都唯一且非空。
(3)聚集索引(又叫聚簇索引):cluster
在聚集索引中,表中行的物理顺序与键值的逻辑(索引)顺序相同。一个表只能包含一个聚集索引。如果某索引不是聚集索引,则表中行的物理顺序与键值得逻辑顺序不匹配。与非聚集索引相比,聚集索引通常提供更快的数据访问
4.索引的实现原理(这里我们能知道为什么索引会加快查询速度)
即二叉搜索树
1.所有非叶子结点至多拥有两个儿子(left和right)
2.所有节点存储一个关键字
3.非叶子节点的左指针指向小于其关键字的子树,右指针指向大于其关键字的子树
B-树(B树)
是一种多路搜索树(并不是二叉的),任意一棵m阶B-树:
1.定义任意非叶子结点最多只有M个儿子;且M>2;
2.根结点的儿子数为[2, M];
3.除根结点以外的非叶子结点的儿子数为[M/2,M];
4.每个结点存放至少M/2-1(取上整)和至多M-1个关键字;(至少2个关键字)
5.非叶子结点的关键字个数=指向儿子的指针个数-1;
6.非叶子结点的关键字:K[1], K[2], …, K[M-1];且K[i] < K[i+1];
7.非叶子结点的指针:P[1], P[2], …, P[M];其中P[1]指向关键字小于K[1]的子树,P[M]指向关键字大于K[M-1]的子树,其它P[i]指向关键字属于(K[i-1], K[i])的子树;
8.所有叶子结点位于同一层;
B+树
B+树是B-树的变体,也是一种多路搜索树:
1.其定义基本与B-树同,除了:
2.非叶子结点的子树指针与关键字个数相同;
3.非叶子结点的子树指针P[i],指向关键字值属于[K[i], K[i+1])的子树(B-树是开区间);
5.为所有叶子结点增加一个链指针;
6.所有关键字都在叶子结点出现;
3、锁:悲观锁、乐观锁
悲观锁:总是假设最坏的情况,每次去拿数据的时候都认为别人会修改,所以每次在拿数据的时候都会上锁,这样别人想拿这个数据就会阻塞直到它拿到锁。传统的关系型数据库里边就用到了很多这种锁机制,比如行锁,表锁等,读锁,写锁等,都是在做操作之前先上锁。再比如Java里面的同步原语synchronized关键字的实现也是悲观锁。
乐观锁:顾名思义,就是很乐观,每次去拿数据的时候都认为别人不会修改,所以不会上锁,但是在更新的时候会判断一下在此期间别人有没有去更新这个数据,可以使用版本号等机制。乐观锁适用于多读的应用类型,这样可以提高吞吐量,像数据库提供的类似于write_condition机制,其实都是提供的乐观锁。在Java中java.util.concurrent.atomic包下面的原子变量类就是使用了乐观锁的一种实现方式CAS实现的。
4、事务:事务的四大特性(ACID)、事务并发的三大问题、事务隔离级别及实现原理
一
原子性:事务是数据库的逻辑工作单位,事务中包含的各操作要么都做,要么都不做。
一致性:事务的执行结果必须是使数据库从一个一致性状态变到另一个一致性状态。因此当数据库只包含成功事务提交的结果时,就说数据库处于一致性状态。如果数据库系统运行中发生故障,有些事务尚未完成就被迫中断,这些未完成事务对数据库所做的修改有一部分已经写入了物理数据库,这时数据库就处于一种不正确的状态,或者说是不一致的状态。
隔离性:一个事务的执行不能受其它事务的干扰。即并发执行的各个事务之间不能互相干扰。
持续性:也称永久性,指一个事务一旦提交,它对数据库中的数据的改变就应该是永久性的。接下来的其它操作或故障不应该对其执行结果有任何影响。
二
脏数据:它所指的就是未提交的数据。也就是说,一个事务正在对一条记录做修改,在这个事务完成并提交之前,这条数据是处于待定状态的(,这时,第二个事务来读取这条没有提交的数据,并据此做进一步的处理,就会产生对未提交的数据的依赖关系。这种现象被称为脏读。
不可重复读(Non-Repeatable Reads):一个事务先后读取同一条记录,事务在两次读取之间该数据被其它事务所修改,则两次读取的数据不同,称之为不可重复读。
幻读(Phantom Reads):一个事务按相同的查询条件重新读取以前检索过的数据,却发现其他事务插入了满足其查询条件的新数据,这种现象就称为幻读。
三
(1)Read uncommitted:读未提交,顾名思义,就是一个事务可以读取另一个未提交事务的数据。
事例:老板要给程序员发工资,程序员的工资是3.6万/月。但是发工资时老板不小心按错了数字,按成3.9万/月,该钱已经打到了程序员的户口,但是事务还没有提交,就在这时,刚好程序员去查看自己这个月的工资,发现比往常多了3千元,以为涨工资了非常高兴。但是老板及时发现了不对,马上回滚差点就提交了的事务,将数字改成3.6万再提交。
分析:实际程序员这个月的工资还是3.6万,但是程序员看到的是3.9万。他看到的是老板还没提交事务时的数据。这就是脏读。
那怎么解决脏读呢?Read committed!读提交,能解决脏读问题。
(2)Read committed:读提交,顾名思义,就是一个事务要等另一个事务提交后才能读取数据。
事例:程序员拿着信用卡去享受生活(卡里当然是只有3.6万),当他买单时(程序员事务开启),收费系统事先检测到他的卡里有3.6万,就在这个时候!!程序员的妻子要把钱全部转出充当家用,并提交该事物。当收费系统准备扣款时,再检测卡里的金额,发现已经没钱了(第二次检测卡里的金额当然要等待妻子转出金额事务提交完,才能检测)。程序员就会很郁闷,明明卡里是有钱的…
分析:这就是读提交,若有事务对数据进行更新(UPDATE)操作时,读操作事务要等待这个更新操作事务提交后才能读取数据,可以解决脏读问题。
但在这个事例中,出现了一个事务范围内两个相同的查询却返回了不同数据,这就是不可重复读。
那怎么解决不可重复读问题?Repeatable read !,重复读。
(3)Repeatable read:重复读,就是在开始读取数据(事务开启)时,不再允许修改操作发生。
事例:程序员拿着信用卡去享受生活(卡里当然是只有3.6万),当他买单时(事务开启,不允许其他事务的UPDATE修改操作),收费系统事先检测到他的卡里有3.6万。这个时候他的妻子不能转出金额了。接下来收费系统就可以扣款了。
分析:重复读可以解决不可重复读问题。写到这里,应该明白的一点就是,不可重复读对应的是修改,即UPDATE操作。但是可能还会有幻读问题。因为幻读问题对应的是插入INSERT操作,而不是UPDATE操作。
什么时候会出现幻读?
事例:程序员某一天去消费,花了2千元,然后他的妻子去查看他今天的消费记录(妻子事务开启),看到确实是花了2千元,就在这个时候(时间间隙),程序员又花了1万买了一部电脑,即新增INSERT了一条消费记录,并提交。当妻子打印程序员的消费记录清单时(妻子事务提交),发现花了1.2万元,似乎出现了幻觉,这就是幻读。
那怎么解决幻读问题?Serializable!
(4)Serializable 序列化:Serializable 是最高的事务隔离级别,在该级别下,事务串行化顺序执行,可以避免脏读、不可重复读与幻读。但是这种事务隔离级别效率低下,比较耗数据库性能,一般不使用。
5、多版本并发控制实现机制(MCVV)原理
首先,在MySQL中,每个表的记录都有两个隐藏字段(trx_id,roll_pointer,当该表没有主键和非null唯一键时还会有一个row_id字段),而MVCC的实现正是基于数据表中数据的隐藏字段来实现的
trx_id:每次对某条索引记录进行修改时,都会把对应的事务id赋值给trx_id隐藏列(每个事务都有一个事务id,且事务id是递增的)
roll_pointer:每次对某条聚簇索引记录进行改动时,都会把旧的版本写入到undo日志中,然后这个隐藏列就相当于一个指针,可以通过它找到该记录修改前的信息
row_id(非必要)当表中没有主键和非null唯一键时才会有row_id字段,该字段作为隐藏主键