深入浅出MySQL:Mysql的的三个核心知识点:一是存储引擎的对比,二是分区的要点,三是索引的使用
(1)
InnoDB:事务性存储引擎,适合做一些经常需要更新和修改的操作当中,一般是行级锁定
MyISAM:非事务性存储引擎,适合做一些插入和读取操作比较频繁当中,一般是表级锁定
(2)
对于分组之后的条件不能再用where筛选而是采用having来筛选;
我们尽可能用where先过滤记录,这样因为结果集减少,将对聚合的效率大大
提高,最后再根据逻辑用having在进行过滤即可
(3)
Mysql在类型后面加的小括号其实是自动补全前面的空白,不是代表这个数据的长度
例如init(5),就代表会为前面带5个0修饰,实际长度还是-21474这么大8648--2147483647
(4)
数据类型的话,如果要求精度很高,则使用定点数(bigDecimal),如果不是那么高,就可以
采用浮点数(double,float)
(5)
最适合做索引的方法是
列是在where子句中的列,或者连接子句中的列,而不是在select后面的列
该列的值越不一样,越适合做索引,像性别这一列就不适用于做索引,因为只有两个,效率不明显
一般是用B-tree索引为主
(6)
Mysql的分区不能只对表分区而不对索引分区,两者必须同样对待。
对于同一个分区表的所有分区,必须使用同一个存储引擎
(7)
无论是哪种Mysql的分区类型,要么分区表上没有主键或者唯一键,否则一定是要以主键作为分区键
(8)
Range分区:利用取值范围将数据分成分区,区间要连续并且不能重叠,使用Values less
than 操作符进行分区定义。优点:当对于百万条数据需要删除某些记录时,直接找到对应的分区
进行删除即可,就不用delete根据id一条条比对了
List分区,采用枚举的形式进行分区
(9)
分表的方式:有垂直拆分和水平拆分
(10)
反规范化在一定程度上起着不错的作用,就是通过增加冗余列来避免多次的连接查询
(11)
负载均衡:利用某种均衡算法,将固定的负载量分布到不同的服务器上,以减轻单台服务器的负载
Mysql的应对措施是,主从复制或者采用分布式架构
(12)
表级锁,开销小,粒度大,并发度最低,其中包括了读锁和写锁
页面锁,开销中,粒度中,并发度中
行级锁,开销大,粒度小,并发度大
(13)
PROPAGATION_REQUIRED--支持当前事务,如果当前没有事务,就新建一个事务。这是最常见的选择。
PROPAGATION_SUPPORTS--支持当前事务,如果当前没有事务,就以非事务方式执行。
PROPAGATION_MANDATORY--支持当前事务,如果当前没有事务,就抛出异常。
PROPAGATION_REQUIRES_NEW--新建事务,如果当前存在事务,把当前事务挂起。
PROPAGATION_NOT_SUPPORTED--以非事务方式执行操作,如果当前存在事务,就把当前事务挂起。
PROPAGATION_NEVER--以非事务方式执行,如果当前存在事务,则抛出异常。
(14)
Mysql语句的执行过程
(15)
两个重要的日志模块,redo log和binlog
两者区别:redo log是在存储引擎层为Innodb引擎特有的,拥有crash-safe能力(即使数据库发生异常重启,之前提交的记录都不会丢失),是物理日志,记录的是“在某个数据页上做了什么修改”
binlog是Server层为所有引擎持有的,没有crash-safe能力,是逻辑日志,记录的是这个语句的原始逻辑,比如“给ID=2这一行的c字段加1 ”。
两者采用的是两阶段提交的方式来保证数据一致性
(16)
Mysql包含4种隔离级别
Read Uncommitted(读取未提交内容),不推荐
Read Committed(不可重复读)读取会不一致,只读取提交事务的值
Repeatable Read(可重复读)读取会一致,因为版本号控制,可重复读的隔离级别下使用了MVCC机制,select操作不会更新版本号,是快照读(历史版本);insert、update和delete会更新版本号,是当前读(当前版本)。
Serializable(可串行化),锁表严重,不推荐
(17)
分析sql语句性能有两种方式,一种是explain关键字分析sql语句,还有一种是启动慢查询日志
(18)
有时候Mysql即使设计了索引但不会使用索引,两种方式,第一种是加force index强制使用索引
select * from t force index(a) where a between 10000 and 20000;/*Q2*/
另一种是引导Mysql使用索引,可以加个order by
(19)
explain主要看三个参数,key看使用了哪个索引,rows看查询了多少行,Extra看是否有排序
(20)
复合索引必须满足最左前缀原则
(21)
如果索引字段在函数内被使用的话,是没有任何效果的
(22)
要选择数据量小的作为驱动表(也就是左边那个表)
(23)
乐观锁和悲观锁的区别?这两种锁在Java和MySQL分别是怎么实现的?
悲观锁假定会发生冲突,访问的时候都要先获得锁,保证同一个时刻只有线程获得锁,读读也会阻塞;乐观锁假设不会发生冲突,只有在提交操作的时候检查是否有冲突Java乐观锁通过CAS实现,悲观锁通过synchronize实现。mysql乐观锁通过MVCC,也就是版本实现,悲观锁可以通过select... for update加上排它锁
(24)
Mysql使用什么引擎?为什么?
支持事务、聚簇索引、MVCC
(25)
在一张表里查询重复的记录
思路:先分组,再having计数
SELECT email from person GROUP BY email having COUNT(eamil) > 1
(26)
事务的基本要素(ACID)
1、原子性(Atomicity):事务开始后所有操作,要么全部做完,要么全部不做,不可能停滞在中间环节。事务执行过程中出错,会回滚到事务开始前的状态,所有的操作就像没有发生一样。也就是说事务是一个不可分割的整体,就像化学中学过的原子,是物质构成的基本单位。
2、一致性(Consistency):事务开始前和结束后,数据库的完整性约束没有被破坏 。比如A向B转账,不可能A扣了钱,B却没收到。
3、隔离性(Isolation):同一时间,只允许一个事务请求同一数据,不同的事务之间彼此没有任何干扰。比如A正在从一张银行卡中取钱,在A取钱的过程结束前,B不能向这张卡转账。
4、持久性(Durability):事务完成后,事务对数据库的所有更新将被保存到数据库,不能回滚。
(27)
事务的并发问题
1、脏读:事务A读取了事务B更新的数据,然后B回滚操作,那么A读取到的数据是脏数据
2、不可重复读:事务 A 多次读取同一数据,事务 B 在事务A多次读取的过程中,对数据作了更新并提交,导致事务A多次读取同一数据时,结果 不一致。
3、幻读:系统管理员A将数据库中所有学生的成绩从具体分数改为ABCDE等级,但是系统管理员B就在这个时候插入了一条具体分数的记录,当系统管理员A改结束后发现还有一条记录没有改过来,就好像发生了幻觉一样,这就叫幻读。
小结:不可重复读的和幻读很容易混淆,不可重复读侧重于修改,幻读侧重于新增或删除。解决不可重复读的问题只需锁住满足条件的行,解决幻读需要锁表
(28)
MySQL事务隔离级别
事务隔离级别 脏读 不可重复读 幻读
读未提交(read-uncommitted) 是 是 是
不可重复读(read-committed) 否 是 是
可重复读(repeatable-read) 否 否 是
串行化(serializable) 否 否 否
总结:虽说串行化可以解决事务并发问题,可是并发程度非常低,一般不会使用,默认的事务隔离级别是可重复读.
可重复读的隔离级别下使用了MVCC机制,select操作不会更新版本号,是快照读(历史版本);insert、update和delete会更新版本号,是当前读(当前版本)。
(29)
两阶段提交试用与分布式事务,用来保证ACID。第一次提交协调者询问参与者是否准备提交或者回滚,第二次提交则执行提交或者回滚操作
(30)
一、悲观锁
顾名思义,就是对于数据的处理持悲观态度,总认为会发生并发冲突,获取和修改数据时,别人会修改数据。所以在整个数据处理过程中,需要将数据锁定。
悲观锁的实现,通常依靠数据库提供的锁机制实现,比如mysql的排他锁,select .... for update来实现悲观锁。
二:乐观锁
顾名思义,就是对数据的处理持乐观态度,乐观的认为数据一般情况下不会发生冲突,只有提交数据更新时,才会对数据是否冲突进行检测。
如果发现冲突了,则返回错误信息给用户,让用户自已决定如何操作。
乐观锁的实现不依靠数据库提供的锁机制,需要我们自已实现,实现方式一般是记录数据版本,一种是通过版本号,一种是通过时间戳。
给表加一个版本号或时间戳的字段,读取数据时,将版本号一同读出,数据更新时,将版本号加1。
当我们提交数据更新时,判断当前的版本号与第一次读取出来的版本号是否相等。如果相等,则予以更新,否则认为数据过期,拒绝更新,让用户重新操作。