分库与分表
1. 分表与分区的不同
分表,就是讲一张表分成多个小表,这些小表拥有不同的表名;而分区是将一张表的数据分为多个区块,这些区块可以存储在同一个磁盘上,也可以存储在不同的磁盘上,这种方式下表仍然只有一个。
2. 使用分库与分表的原因
随着时间和业务的发展,数据库中的表会越来越多,并且表中的数据量也会越来越大,那么读写操作的开销也会随着增大。
3. 垂直切分
将表按功能模块、关系密切程度划分出来,部署到不同的库上。例如,我们会建立商品数据库 payDB、用户数据库 userDB 等,分别用来存储项目与商品有关的表和与用户有关的表。
4. 水平切分
把表中的数据按照某种规则存储到多个结构相同的表中,例如按 id 的散列值、性别等进行划分,
5. 垂直切分与水平切分的选择
如果数据库中的表太多,并且项目各项业务逻辑清晰,那么垂直切分是首选。
如果数据库的表不多,但是单表的数据量很大,应该选择水平切分。
6. 水平切分的实现方式
最简单的是使用 merge 存储引擎。
7. 分库与分表存在的问题
(1) 事务问题
在执行分库分表之后,由于数据存储到了不同的库上,数据库事务管理出现了困难。如果依赖数据库本身的分布式事务管理功能去执行事务,将付出高昂的性能代价;如果由应用程序去协助控制,形成程序逻辑上的事务,又会造成编程方面的负担。
(2) 跨库跨表连接问题
在执行了分库分表之后,难以避免会将原本逻辑关联性很强的数据划分到不同的表、不同的库上。这时,表的连接操作将受到限制,我们无法连接位于不同分库的表,也无法连接分表粒度不同的表,导致原本只需要一次查询就能够完成的业务需要进行多次才能完成。
两阶段锁协议
加锁阶段:在该阶段可以进行加锁操作。在对任何数据进行读操作之前要申请并获得S锁,在进行写操作之前要申请并获得X锁。加锁不成功,则事务进入等待状态,直到加锁成功才继续执行。
解锁阶段:当事务释放了一个*以后,事务进入解锁阶段,在该阶段只能进行解锁操作不能再进行加锁操作。
1.扩展阶段
在对任何数据项的读、写之前,要申请并获得该数据项的*。
2.收缩阶段
每个事务中,所有的*请求必须先于解锁请求。
在InnoDB事务中,行锁是在需要的时候才加上的,但不是不需要了就可以立马释放,而是要等到事务结束时才释放。这个就是两阶段锁协议。
mysql有哪些事物隔离级别
未提交读
就是比如原先name的值是小刚,然后有一个事务B`update table set name = '小明' where id = 1`,它还没提交事务。同时事务A也起了,有一个select语句`select name from table where id = 1`,在这个隔离级别下获取到的name的值是小明而不是小刚。那万一事务B回滚了,实际数据库中的名字还是小刚,事务A却返回了一个小明,这就称之为脏读。
已提交读:
只能读其他事物提交过的数据。但此时会出现一个问题,不可重复读。如下图所示相同查询获取结果不同。
·
可重复读
一个事务启动的时候,能够看到所有已经提交的事务结果。但是之后这个事务执行期间,其他的事务更新对他不可见。
这和已提交读的区别就在于,它重复读取的值是不变的。所以取了个贴切的名字叫可重复读。但是会出现幻读
串行化读
串行化格式下就只能进行读-读并发。只要有一个事务操作一条记录的写,那么其他要访问这条记录的事务都得等着。直到该事物提交。
脏读 :读到别的事务没有提交的数据
不可重复度:同一事务中,相同的查询范围,同一个数据资源莫名其妙的改变了侧重于值的新。
幻读:在同一事务中,相同的查询语句,第二次查询是发现多出一些数据或者者不见了一些数据(侧重于增加删除)。
MVCC实现已提交读和可重复读。
在实现上,数据库里面会创建一个视图,访问的时候以视图的逻辑结果为准。在“可重复读”隔离级别下,这个视图是在事务启动时创建的,整个事务存在期间都用这个视图。在“读提交”隔离级别下,这个视图是在每个 SQL 语句开始执行的时候创建的。这里需要注意的是,“读未提交”隔离级别下直接返回记录上的最新值,没有视图概念;而“串行化”隔离级别下直接用加锁的方式来避免并行访问。
解决幻读
- MVCC+next-key locks:next-key locks由record locks(索引加锁) 和 gap locks(间隙锁,每次锁住的不光是需要使用的数据,还会锁住这些数据附近的数据)
一条SQL执行的很慢的原因?
偶尔很慢 ::刷新脏页 被别人锁住了如表锁行锁
当我们要往数据库插入一条数据、或者要更新一条数据的时候,我们知道数据库会在内存中把对应字段的数据更新了,但是更新之后,这些更新的字段并不会马上同步持久化到磁盘中去,而是把这些更新的记录写入到 redo log 日记中去,等到空闲的时候,在通过 redo log 里的日记把最新的数据同步到磁盘中去。
redolog写满了:redo log 里的容量是有限的,如果数据库一直很忙,更新又很频繁,这个时候 redo log 很快就会被写满了,这个时候就没办法等到空闲的时候再把数据同步到磁盘的,只能暂停其他操作,全身心来把数据同步到磁盘中去的,而这个时候,就会导致我们平时正常的SQL语句突然执行的很慢,所以说,数据库在在同步数据到磁盘的时候,就有可能导致我们的SQL语句执行的很慢了。
内存不够用了:如果一次查询较多的数据,恰好碰到所查数据页不在内存中时,需要申请内存,而此时恰好内存不足的时候就需要淘汰一部分内存数据页,如果是干净页,就直接释放,如果恰好是脏页就需要刷脏页。
MySQL 认为系统“空闲”的时候:这时系统没什么压力。
MySQL 正常关闭的时候:这时候,MySQL 会把内存的脏页都 flush 到磁盘上,这样下次 MySQL 启动的时候,就可以直接从磁盘上读数据,启动速度会很快。
一直很慢:没使用索引(优化器部分)
where 条件 含有表达式 使用了函数
不符合最左索引匹配原则
没有索引
不会触发查询缓存却一直要维护缓存
查询缓存是有一个哈希值索引,这个哈希值通过查询本身、当前要查询的数据库、客户端协议版本号等一些可能影响结果的 信息计算得来。所以两个SQL语句在任何字符上的不同(例如:空格、注释),都会导致缓存不会命中。 更新表也会导致缓存失效。
MySQL有哪些存储引擎以及他们之间的区别
InnoDB 支持行锁,Myisam不支持行锁
InnoDB 是事务型的。实现了四个标准的隔离级别,默认级别是可重复读。表是基于聚簇索引建立的,它对主键的查询性能有很高的提升。
InnoDB 支持在线热备份。
MyISAM 设计简单 非聚簇索引
MyISAM 只支持表级锁,而 InnoDB 还支持行级锁。
MyISAM 支持全文索引,地理空间索引;
InnoDB支持外键,MyISAM不支持
为什么索引能加快查找效率?
不使用索引的时候使用顺序遍历,o(n)。使用索引,InnoDB的索引模型是b+树,b+树的搜索近似二分查找o(logn)。
为什么说B+tree比B树更适合实际应用中操作系统的文件索引和数据库索引?
B+tree的磁盘读写代价更低 B+tree的内部结点并没有指向关键字具体信息的指针。因此其内部结点相对B 树更小。如果把所有同一内部结点的关键字存放在同一盘块中,那么盘块所能容纳的关键字数量也越多。一次性读入内存中的需要查找的关键字也就越多。相对来说IO读写次数也就降低了。
B树在提高了磁盘IO性能的同时并没有解决元素遍历的效率低下的问题。正是为了解决这个问题,B+树应运而生。B+树只要遍历叶子节点就可以实现整棵树的遍历,支持基于范围的查询,而B树不支持range-query这样的操作(或者说效率太低)。
B+树查询效率稳定,都是到叶子结点才能查询成功。
了解MySQL事务吗?说说ACID是啥
1、原子性(Atomicity):事务开始后所有操作,要么全部做完,要么全部不做,不可能停滞在中间环节。事务执行过程中出错,会回滚到事务开始前的状态,所有的操作就像没有发生一样。也就是说事务是一个不可分割的整体,就像化学中学过的原子,是物质构成的基本单位。
2、一致性(Consistency):事务开始前和结束后,数据库的完整性约束没有被破坏 。由一个一致性状态到另一个一致性状态。比如A向B转账,不可能A扣了钱,B却没收到。
3、隔离性(Isolation):同一时间,只允许一个事务请求同一数据,不同的事务之间彼此没有任何干扰。
4、持久性(Durability):事务完成后,事务对数据库的所有更新将被保存到数据库,不能回滚。
二叉搜索树更新和查询的时间复杂度均为O(logN),那么为什么不用二叉搜索树作为索引模型却选择了B+树?
1.二叉树效率高,但是树高太高,每次指针查找大概率都是触发随机磁盘读,频繁的磁盘读取使得效率变低;
2.N叉树,把整棵树的高度维持在很小范围内,同时在内存中缓存前面若干层的节点,可以极大的降低访问磁盘的次数,提高读的效率;
为什么B+树在数据库索引中用的比较多?
因为平时SELECT取的时候一般取的不是一条数据,而是相邻的多条数据。
如果是多条的话B树需要做局部的中序遍历,可能要跨层访问,而B+树都集中在叶子结点而且有链表结构很方便的可以把一段数据取出来。
既然路数越多,树的高度越低,那么B树为什么不设计成无数多路?
1.这样搜索树就退化成有序数组,而B树是用在文件系统的索引等中。而文件系统和数据库的索引都是在硬盘上的,如果数据量太大,不一定能一次性加载到内存中。此时B树的多路存储就发挥作用了,每次加载树的一个结点,然后一步步的往下找。而如果内存一次只能加载两个数,长的有序数组是无法一次加载进内存的。如果我们把它组织成一个三路的B树,这样每个结点最多有两个数。这样每次加载一个结点就可以了。当涉及到磁盘操作时,B树(多叉)比红黑树(二叉)更有效率,因为一个结点中的内容更多,减少了磁盘IO操作。
2.有序数组更新太慢!
Explain 和profile的使用(如何查看SQL语句的执行状态,知道这条命令吗?)
在之后的版本被Performance Schema代替
show profile; 查看上一条语句执行情况
Type 字段
Ref查找一个索引 range 查找索引范围 index 遍历索引树 all 全表扫描
. Explain
用来分析 SQL 语句,分析结果中比较重要的字段有:
- select_type : 查询类型,有简单查询、联合查询和子查询
- key : 使用的索引
- rows : 扫描的行数