八股文
mysql 篇
基础
数据3大范式
-
第一范式:要求任何一张表必须有主键,每一个字段原子性不可再分
-
第二范式:建立在第一范式的基础之上,要求所有非主键字段完全依赖主键,不要产生部分依赖。
-
第三范式:建立在第二范式的基础上,要求所有非主键字段直接依赖主键,不要产生传递依赖
简述在 MySQL 数据库中 MyISAM 和 InnoDB 的区别
1、事务支持: InnoDB支持事务,而MyISAM不支持。
2、行级锁和表级锁: InnoDB提供行级锁,MyISAM提供表级锁。
3、外键支持: InnoDB支持外键约束,MyISAM不支持。
4、全文索引: MyISAM支持全文索引,而InnoDB在较早版本中不支持。
5、数据恢复: InnoDB提供事务日志,支持崩溃恢复。
6、存储限制: MyISAM支持较大的表,而InnoDB的表大小受到文件系统的限制。
- InnoDB 是聚集索引,数据文件是和索引绑在一起的,必须要有主键,通过主键索引效率很高;MyISAM 是非聚集索引,数据文件是分离的,索引保存的是数据文件的指针,主键索引和辅助索引是独立的。
MySQL 面试题及答案整理,最新面试题 | 弟弟快看-教程 (ddkk.com)
用 InnoDB 引擎都是最合适的,InnoDB 也是 MySQL 的默认存储引擎。
SQL 约束有哪几种?
1、主键约束(Primay Key Coustraint) 唯一性,非空性
2、唯一约束 (Unique Counstraint)唯一性,可以空,但只能有一个
3、检查约束 (Check Counstraint)对该列数据的范围、格式的限制(如:年龄、性别等)
4、默认约束 (Default Counstraint)该数据的默认值
5、外键约束 (Foreign Key Counstraint)需要建立两表间的关系并引用主表的列
原文链接:https://blog.csdn.net/qq_32907195/article/details/106852336
MySQL 中的 varchar 和 char 有什么区别?
char 是一个定长字段,假如申请了char(10)
的空间,那么无论实际存储多少内容.该字段都占用 10 个字符,而 varchar 是变长的,也就是说申请的只是最大长度,占用的空间为实际字符长度+1
区别二:存储容量不同
- 对于char类型来说,最多只能存放的字符个数为255,和编码无关。
- varchar最多能存放65532个字符。VARCHAR的最大有效长度由最大行大小和使用的字符集来确定。整体最大长度是65,532字节。
在检索效率上来讲,char > varchar,因此在使用中,如果确定某个字段的值的长度,可以使用 char,否则应该尽量使用 varchar.例如存储用户 MD5 加密后的密码,则应该使用 char。
MySQL中 in 和 exists 区别
MySQL中的in语句是把外表和内表作hash 连接,而exists语句是对外表作loop循环,每次loop循环再对内表进行查询。
select * from A where id in(select id from B)
有两点区别:
(1) 使用上的区别:exists中放一个子查询有记录返回true,无记录返回false(NULL也算有记录),in中查询结果集只能有一个字段
(2) 性能上的区别:in要把缓存到内存中,exists不需要缓存结果
in()适合B表比A表数据小的情况
exists()适合B表比A表数据大的情况
当A表数据与B表数据一样大时,in与exists效率差不多,可任选一个使用.
not in 和not exists:如果查询语句使用了not in,那么内外表都进行全表扫描,没有用到索引;而not extsts的子查询依然能用到表上的索引。所以无论那个表大,用not exists都比not in要快
MySQL 执行查询的过程
使用自增主键有什么好处?
自增主键可以让主键索引尽量地保持递增顺序插入,避免了页分裂,因此索引更紧凑,在查询的时候,效率也就更高。
说说count(1)、count(*)和count(字段名)的区别
嗯,先说说count(1) and count(字段名)的区别。
两者的主要区别是
- count(1) 会统计表中的所有的记录数,包含字段为null 的记录。
- count(字段名) 会统计该字段在表中出现的次数,忽略字段为null 的情况。即不统计字段为null 的记录。
接下来看看三者之间的区别。
执行效果上:
- count(*)包括了所有的列,相当于行数,在统计结果的时候,不会忽略列值为NULL
- count(1)包括了忽略所有列,用1代表代码行,在统计结果的时候,不会忽略列值为NULL
- count(字段名)只包括列名那一列,在统计结果的时候,会忽略列值为空(这里的空不是只空字符串或者0,而是表示null)的计数,即某个字段值为NULL时,不统计。
执行效率上:
- 列名为主键,count(字段名)会比count(1)快
- 列名不为主键,count(1)会比count(列名)快
- 如果表多个列并且没有主键,则 count(1) 的执行效率优于 count(*)
- 如果有主键,则 select count(主键)的执行效率是最优的
- 如果表只有一个字段,则 select count(*)最优
truncate、delete与drop区别?
相同点:
truncate
和不带where
子句的delete
、以及drop
都会删除表内的数据。drop
、truncate
都是DDL
语句(数据定义语言),执行后会自动提交。
不同点:
- truncate 和 delete 只删除数据不删除表的结构;drop 语句将删除表的结构被依赖的约束、触发器、索引;
- 一般来说,执行速度: drop > truncate > delete。
1. 索引
索引优势和劣势
优势:
提高数据检索的效率,降低数据库的IO成本;
通过索引列对数据进行排序,降低数据排序的成本,降低了CPU的消耗
劣势:
会降低更新表的速度,如对表进行INSERT、UPDATE和DELETE
索引也要占用一部分存储空间
索引分类
2)唯一索引(UNIQUE)
避免同一个表中某数据列中的值重复;主键索引只能有一个,唯一索引可以有多个;
索引列的值必须唯一,且允许有null值;
3)组合索引(多个列联合索引)
组合索引遵循最左前缀的标准,专门用于组合搜索,其效率大于索引合并;
4)常规索引(INDEX)
快速定位特定数据;常加在查询条件的字段,不易添加太多的常规索引,影响数据的插入、更新和删除操作;
5)全文索引(FULLTEXT)
快速定位特定数据,只能用于MyISAM存储引擎的数据表,只能用于CHAR、VARCHAR、TEXT数据列类型,常使用大型数据集;
为什么选择B+树作为索引结构,而不是用别的数据结构
-
哈希表的特点就是可以快速的精确查询,但是不支持范围查询:《爱上面试官》系列-数据库索引 (qq.com)
-
平衡二叉树插入或者更新时,需要左旋右旋维持平衡,维护代价大。如果数量多的话,树的高度会很高。因为数据是存在磁盘的,以它作为索引结构,每次从磁盘读取一个节点,操作IO的次数就多啦
不选b树原因:
-
B+树非叶子节点上是不存储数据的,仅存储键值,而B树节点中不仅存储键值,也会存储数据。如果不存储数据,那么就会存储更多的键值,相应的树的阶数(节点的子节点树)就会更大,树就会更矮更胖,如此一来我们查找数据进行磁盘的IO次数有会再次减少,数据查询的效率也会更快.
-
B+树索引的所有数据均存储在叶子节点,而且数据是按照顺序排列的,链表连着的。面试-mysql-索引篇 - 伏地僧 - 博客园 (cnblogs.com)
为什么选择B+ 树作为索引结构。
- 高效的查询性能:B+树是一种平衡树,每个节点都有相同的高度,这使得在B+树中查找数据的时间复杂度为O(logN),其中N为数据量。因此,B+树能够快速地查找数据。
- 支持范围查询:B+树中的叶子节点存储了所有的数据,而且数据按照键值有序排列。这使得B+树能够支持范围查询,即查询某个范围内的数据。
- 支持高效的数据插入和删除:B+树的平衡性使得在插入或删除数据时,只需要对少数几个节点进行调整,而不需要对整棵树进行重新平衡。这使得B+树能够高效地处理数据的插入和删除操作。
- 支持高效的磁盘访问:B+树中的节点通常比较大,可以存储多个数据项。这样可以减少磁盘I/O的次数,从而提高磁盘访问的效率。同时,B+树的叶子节点形成了一个有序的链表,可以很容易地进行顺序访问。
一个B+树的节点中到底存储多少个元素合适呢?
回答:B+树中一个节点为一页或页的倍数最为合适。因为如果一个节点的大小小于1页,那么读取这个节点的时候其实也会读出1页,会造成资源的浪费;如果一个节点的大小大于1页,比如1.2页,那么读取这个节点的时候会读出2页,也会造成资源的浪费;所以为了不造成资源的浪费,最后把一个节点的大小控制在1页、2页、3页、4页等倍数页大小最为合适
为什么B+树中一个节点为1页(16K)
对着上面Mysql中Innodb中对B+树的实际应用(主要看主键索引),可以发现B+树中的一个节点存储的内容是:
1. 非叶子节点:主键 + 指针
2. 叶子节点:数据
那么,假设我们一行数据大小为1K,那么一页就能存16条数据,也就是一个叶子节点能存16条数据;再看非叶子节点,假设主键ID为bigint类型,那么长度为8B,指针大小在Innodb源码中为6B,一共就是14B,那么一页里就可以存储16K/14=1170个(主键+指针),那么一颗高度为2的B+树能存储的数据为:1170 * 16=18720条,一颗高度为3的B+树能存储的数据为:1170 * 1170 * 16=21902400(千万级条)。所以在InnoDB中B+树高度一般为1-3层,它就能满足千万级的数据存储。在查找数据时一次页的查找代表一次IO,所以通过主键索引查询通常只需要1-3次IO操作即可查找到数据。所以也就回答了我们的问题,1页=16k这么设置是比较合适的
为什么MySQL的索引要使用B+树而不是其它树形结构?比如B树?
因为B树不管叶子节点还是非叶子节点,都会保存数据,这样导致在非叶子节点中能保存的指针数量变少,指针少的情况下要保存大量数据,只能增加树的高度,导致IO操作变多,查询性能变低;
最左前缀索引规则
如果索引关联了多列(联合索引),要遵守最左前缀法则,最左前缀法则指的是查询从索引的最左列开始,并且不跳过索引中的列。
如果跳跃某一列,索引将部分失效(后面的字段索引失效)。
联合索引中,出现范围查询(<, >),范围查询右侧的列索引失效。可以用>=或者<=来规避索引失效问题
20.为什么要遵守最左前缀原则才能利用到索引?_哔哩哔哩_bilibili
创建组合索引,以最左边的为准,只要查询条件中带有最左边的列,那么查询就会使用到索引
索引失效情况
- 在索引列上进行运算操作,索引将失效。如:
explain select * from tb_user where substring(phone, 10, 2) = '15';
- 字符串类型字段使用时,不加引号,索引将失效。如:
explain select * from tb_user where phone = 17799990015;
,此处phone的值没有加引号 - 模糊查询中,如果仅仅是尾部模糊匹配,索引不会是失效;如果是头部模糊匹配,索引失效。如:
explain select * from tb_user where profession like '%工程';
,前后都有 % 也会失效。 - 用 or 分割开的条件,如果 or 其中一个条件的列没有索引,那么涉及的索引都不会被用到。
- 联合索引,查询时的条件列不是联合索引中的第一个列,索引失效。
哪些情况下适合建立索引?
1)主键自动建立唯一索引;
2)频繁作为查询条件的字段应该创建索引;
3)查询中与其他表关联的字段,外键关系建立索引;
4)单键/组合索引的选择问题,组合索引性价比更高;
5)查询中排序的字段,排序字段若通过索引去访问将大大提高排序速度;
6)查询中统计或者分组字段;
哪些情况下不适合建立索引?
1)表字段太少(一般建议在表中数据有2000行时,建立索引);
2)经常增删改的表或者字段;
3)Where条件里用不到的字段不创建索引;
4)过滤性不好的不适合建立索引(过滤性不好即为区分度太差的字段,比如:性别)
为什么需要使用联合索引?
- 减少开销。建一个联合索引(col1,col2,col3),实际相当于建了(col1),(col1,col2),(col1,col2,col3)三个索引。每多一个索引,都会增加写操作的开销和磁盘空间的开销。对于大量数据的表,使用联合索引会大大的减少开销!
- 覆盖索引。对联合索引(col1,col2,col3),如果有如下的sql: select col1,col2,col3 from test where col1=1 and col2=2。那么MySQL可以直接通过遍历索引取得数据,而无需回表,这减少了很多的随机io操作。减少io操作,特别的随机io其实是dba主要的优化策略。所以,在真正的实际应用中,覆盖索引是主要的提升性能的优化手段之一。
如果一张表数据量级是千万级别以上的,那么,给这张表添加索引,你需要怎么做呢?
- 1.先创建一张跟原表A数据结构相同的新表B。
- 2.在新表B添加需要加上的新索引。
- 3.把原表A数据导到新表B
- 4.rename新表B为原表的表名A,原表A换别的表名;
面试-mysql-索引篇 - 伏地僧 - 博客园 (cnblogs.com)
索引覆盖
聚集索引(主键索引):
聚集索引就是按照每张表的主键构造一颗B+树,同时叶子节点中存放的即为整张表的记录数据。
聚集索引的叶子节点称为数据页,聚集索引的这个特性决定了索引组织表中的数据也是索引的一部分。
辅助索引(二级索引):
非主键索引,叶子节点=键值+主键索引值。Innodb存储引擎的书签就是相应行数据的主键索引值。
- 解释一: 就是select的数据列只用从索引中就能够取得,不必从数据表中读取,换句话说查询列要被所使用的索引覆盖。
- 比如简历bcd 联合索引,此时select b from t;此时就可以使用索引覆盖,不需要回表查询
索引下推
在对联合索引遍历过程中,对索引中包含的所有字段先做判断,过滤掉不符合条件的记录之后再回表,能有效的减少回表次数:mysql5.6以后出来的====简单理解:下推其实就是指将部分上层(服务层)负责的事情,交给了下层(引擎层)去处理。using_index_condition
无索引下推:
索引下推:
MyISAM和InnoDB的索引区别_innodb和myisam索引的区别-CSDN博客
一是主索引的区别,InnoDB的数据文件本身就是索引文件。而MyISAM的索引和数据是分开的。
二是辅助索引的区别:InnoDB的辅助索引data域存储相应记录主键的值而不是地址。而MyISAM的辅助索引和主索引没有多大区别
innodb是聚簇索引:数据和索引在一起,myisam 是非聚簇索引:数据和索引分开
9. InnoDB的索引和MyISAM的索引有什么区别?_哔哩哔哩_bilibili
聚簇索引和非聚簇索引区别
为什么order by 索引会失败? 从非聚集索引和索引覆盖考虑
数据 a b c d e a:主键, bcd 联合索引 e:没有索引
select * from t order by b,c,d; 走bcd 索引不需要排序,因为bcd 联合索引以非聚簇索引形式存在,mysql 底层以bcd 字段建立B+树,B+树叶子节点存储:键值(bcd) +主键索引值 ; 而b+树叶子节点本身就排序了。所以排序无用。 同时非聚簇索引,查询完整的数据需要回表操作。
select * from t order by b,c,d;
此时走索引== 走bcd 索引,不排序+回表
全部扫表 额外排序内存+ 不用回表,可以看到 全表扫表更快。所以此时走全表扫表
select b from t order by b ,c,d;
此时根据上面的分析他会使用索引覆盖,不需要排序,不需要回表,此时就会使用索引。
****
如何为省份证添加索引
如何给特殊字符串加索引:如身份证、邮箱等_身份证号如何建立索引-CSDN博客
-
直接邮箱添加索引
select * from user where email = '[email protected]'
叶子节点存放的就是email的完整值,在非聚集索引里根据email查到了主键id=1,然后进行回表,这里发生一次回表
-
前缀索引email(4)
select * from user where email = '[email protected]'
因为叶子节点只会存放email前四个字节的值,所以在非聚集索引里查到四条记录,还要进行四次回表操作,比对email=‘[email protected]’记录进行筛选。
因为email长度截取了,那么b+tree每个节点存储键值数量多了,树高就低了,那么带来的问题就是,增加了回表的次数。
身份证字段建立索引
身份证长度为18,不适合作为索引。身份证号码特点:前6位代表地址,中间8位为年月日
倒序存储
因为身份证后六位区分度高,那么我们可以将身份证倒序存储,然后索引为id_card(6)
select * from user where id_card = reverse('输入的正序身份证号码');
倒序存储只适用等值查询
哈希
可以新增一个字段存储身份证号码的哈希值,加上索引,存入身份证时候,对身份证进行crc3()计算,得到的值存入id_card_crc,索引长度为4,因为hash可能会发生碰撞,所以查询时候加上身份证作为筛选条件:
select * from user where id_card_crc = crc32("输入的身份证号码") and id_card = '输入身份证号';
哈希存储只适用等值查询。
什么情况下会发生明明创建了索引,但是执行的时候并没有通过索引呢
一条SQL语句的查询,可以有不同的执行方案,至于最终选择哪种方案,需要通过优化器进行选择,选择执行成本最低的方案
- 根据搜索条件,找出所有可能使用的索引
- 计算全表扫描的代价
为什么推荐主键自增
因为InnoDB的索引是按大小排好序的,插入的新数据如果主键是自增的,那么只需要按顺序往后写入即可,性能会比较高,而如果每次插入的主键是跳跃式的,那么就会涉及到上面说的页分裂,需要挪动数据,性能就会受到影响
2. 事务
1. MySQL 四种隔离级别详解,看完吊打面试官 - 菜鸟的奋斗之路 - 博客园 (cnblogs.com)
事务4个特性
事务具有四个特征: 原子性( Atomicity )、一致性( Consistency )、隔离性( Isolation )和持续性( Durability )
- 原子性。事务是数据库的逻辑工作单位,事务中包含的各操作要么都做,要么都不做。
- 一致性。事务执行的结果必须是使数据库从一个一致性状态变到另一个一致性状态
- 隔离性。一个事务的执行不能其它事务干扰.当多个事务同时进行时,就有可能出现
脏读(dirty read)
、不可重复读(non-repeatable read)
、幻读(phantom read)
- 持续性。也称永久性,指一个事务一旦提交,它对数据库中的数据的改变就应该是永久性的
MySQL 四种隔离级别详解,看完吊打面试官 - 菜鸟的奋斗之路 - 博客园 (cnblogs.com)
并发导致事务3个问题
脏读:事务 A 读取了事务 B 更新后的数据,但是事务 B 没有提交,然后事务 B 执行回滚操作,那么事务 A 读到的数据就是脏数据
不可重复读:事务 A 进行多次读取操作,事务 B 在事务 A 多次读取的过程中执行更新操作并提交,提交后事务 A 读到的数据不一致。:简单 多次读取同一数据,不一致。 数据不相同
幻读:事务 A 将数据库中所有学生的成绩由 A -> B,此时事务 B 手动插入了一条成绩为 A 的记录,在事务 A 更改完毕后,发现还有一条记录没有修改,那么这种情况就叫做出现了幻读。: 多次查询数据,数量不一致。即行数不一致
4种隔离级别
SQL的隔离级别有四种,它们分别是读未提交(read uncommitted)
、读已提交(read committed)
、可重复读(repetable read)
和 串行化(serializable)
.
读未提交:读未提交指的是一个事务在提交之前,它所做的修改就能够被其他事务所看到。
读已提交:读已提交指的是一个事务在提交之后,它所做的变更才能够让其他事务看到。
可重复读:可重复读指的是一个事务在执行的过程中,看到的数据是和启动时看到的数据是一致的。未提交的变更对其他事务不可见。
串行化:顾名思义是对于同一行记录,写
会加写锁
,读
会加读锁
。当出现读写锁冲突的时候,后访问的事务必须等前一个事务执行完成,才能继续执
未提交读:只有写的时候的行级锁。
读已提交:MVCC每次读都进行一次快照,行级锁。
可重复读:MVCC事务中的第一次读会对事务进行快照,行级锁间隙锁。
可串行化:表锁。
MySQL 的隔离级别是基于锁实现的吗
MySQL 的隔离级别基于锁和 MVCC 机制共同实现的。
SERIALIZABLE 隔离级别是通过锁来实现的,READ-COMMITTED 和 REPEATABLE-READ 隔离级别是基于 MVCC 实现的。不过, SERIALIZABLE 之外的其他隔离级别可能也需要用到锁机制,就比如 REPEATABLE-READ 在当前读情况下需要使用加锁读来保证不会出现幻读
Mysql 面试题(一网打尽,收藏版) - 疯狂创客圈 - 博客园 (cnblogs.com)
3. 锁
mysql 锁有哪些
(1)表级锁:开销小,加锁快;不会出现死锁;锁定粒度大,发生锁冲突的概率最高,并发度最低。
(2)行级锁:开销大,加锁慢;会出现死锁;锁定粒度最小,发生锁冲突的概率最 低,并发度也最高。
(3)页面锁:开销和加锁时间界于表锁和行锁之间;会出现死锁;锁定粒度界于表 锁和行锁之间,并发度一般
读锁和写锁
总结:共享锁和共享锁之间不冲突,排他锁和共享锁、排他锁都冲突。默认select的时候是不加锁的,更新、添加、删除的时候会加排他锁。
乐观锁和悲观锁
乐观锁:在操作同一数据时,都认为他人不会对数据进行操作,所以不会对数据进行上锁,但是在做数据更新的时候会判断是否有其他人已经同时更新或已经更新完这个数据。
【面试必备】乐观锁VS悲观锁,你真的了解吗_乐观锁和悲观锁-CSDN博客
乐观锁适用于读多写少的情况下,例如网站的浏览量统计。悲观锁适用于读写频繁的情况下,例如银行系统的转账操作
乐观锁的实现方式主要有两种:CAS机制和版本号机制
CAS机制
1.如果内存位置V的值等于预期的A值,则将该位置更新为新值B,否则不进行任何操作。许多CAS的操作是自旋的:如果操作不成功,会一直重试,直到操作成功为止
CAS包含了Compare和Swap两个操作,它又如何保证原子性呢?答案是:CAS是由CPU支持的原子操作,其原子性是在硬件层面进行保证的
缺点:
ABA问题
假设有两个线程——线程1和线程2,两个线程按照顺序进行以下操作:
(1)线程1读取内存中数据为A;
(2)线程2将该数据修改为B;
(3)线程2将该数据修改为A;
(4)线程1对数据进行CAS操作
在第(4)步中,由于内存中数据仍然为A,因此CAS操作成功,但实际上该数据已经被线程2修改过了。这就是ABA问题
ABA却会带来隐患,例如栈顶问题:一个栈的栈顶经过两次(或多次)变化又恢复了原值,但是栈可能已发生了变化
解决办法:ABA问题,比较有效的方案是引入版本号,内存中的值每发生一次变化,版本号都+1;在进行CAS操作时,不仅比较内存中的值,也会比较版本号,只有当二者都没有变化时,CAS才能执行成功。
高竞争下的开销问题
在并发冲突概率大的高竞争环境下,如果CAS一直失败,会一直重试,CPU开销较大
针对这个问题的一个思路是引入退出机制,如重试次数超过一定阈值后失败退出。当然,更重要的是避免在高竞争环境下使用乐观锁。
原文链接:https://blog.csdn.net/Vermont_/article/details/116802124
版本号机制
版本号机制的基本思路是在数据中增加一个字段version,表示该数据的版本号,每当数据被修改,版本号加1。当某个线程查询数据时,将该数据的版本号一起查出来;当该线程更新数据时,判断当前版本号与之前读取的版本号是否一致,如果一致才进行操作。
记录锁、间隙锁、临键锁,共享锁、排他锁,意向锁
对数据库的操作有读、写,组合起来就有 读读、读写、写读、写写,读读不存在安全问题,安全问题加锁都可以解决,但所有的操作都加锁太重了,只有写写必须要求加锁,读写、写读可以用MVCC。MySQL的默认隔离级别是RR,但是RR在MVCC的加持下还是存在幻读,这时候就还是需要加锁,间隙锁就是用来在RR级别下解决幻读的问题。
记录锁(Record Locks):记录锁是基于索引记录上的锁,它锁定的行数是固定的、明确的,根据情况它可以是共享锁、排他锁。
间隙锁(Gap Locks):间隙锁的目的是在RR级别下,防止幻读的产生是当前事务多次的查询结果数量上不一致,间隙锁的目的就是保证当前范围内的数据不会被更改,所以它会锁住某些个区间的数据。
临键锁(Next-key Locks):等于 记录锁+间隙锁,所以我们只需要知道这两个锁的定义就好了,MySQL默认级别是RR、默认锁上临键锁。
锁都是基于索引去找到数据记录再加锁的,而索引的规则是:通过其它索引找到主键索引,所以:
- 没有使用索引做更新相关操作会锁表。
- 通过唯一/主键索引等值加锁,只会锁具体的行,非唯一索引则不一定,SQL优化器会基于数据分布选择记录锁,或临键锁。
- 只有在RR级别下才有间隙锁,目的是为了解决幻读,如果操作的数据是跨多个范围,就会加多个区间的间隙锁。
- MySQL默认的锁就是【临键锁】,所以在执行SQL的时候,记录锁和间隙锁是会同时存在的。范围是左开右闭的区间
在SQL查询的时候,我们知道是先通过索引去找数据的,其实加锁也是基于索引的,通过索引找到对应的数据然后把相关的数据行都锁上,如果没有使用索引就会扫描全表,也就会锁表。
间隙锁 是左开右开的区间,但间隙锁和临键锁一起的,而临键锁是左开右闭
MySQL有哪些锁? - kisshappyboy - 博客园 (cnblogs.com)
MySQL是如何实现事务隔离级别的MVCC?
InnoDB 的MVCC
是通过 read view
和版本链实现的,版本链保存有历史版本记录,通过read view
判断当前版本的数据是否可见,如果不可见,再从版本链中找到上一个版本,继续进行判断,直到找到一个可见的版本。
MySQL高频面试题_牛客网 (nowcoder.com):强烈推荐
Mysql 隔离级别及实现(MVCC)_mysql mvcc 隔离级别-CSDN博客
MySQL是如何实现事务隔离级别的——详解MVCC原理_事物隔离级别 读未提交-CSDN博客
快照读和当前读
表记录有两种读取方式。
- 快照读:读取的是快照版本。普通的
SELECT
就是快照读。通过mvcc来进行并发控制的,不用加锁。 - 当前读:读取的是最新版本。
UPDATE、DELETE、INSERT、SELECT … LOCK IN SHARE MODE、SELECT … FOR UPDATE
是当前读。
快照读情况下,InnoDB通过mvcc
机制避免了幻读现象。而mvcc
机制无法避免当前读情况下出现的幻读现象。因为当前读每次读取的都是最新数据,这时如果两次查询中间有其它事务插入数据,就会产生幻读。
快照读情况下,InnoDB通过mvcc
机制避免了幻读现象。而mvcc
机制无法避免当前读情况下出现的幻读现象。因为当前读每次读取的都是最新数据,这时如果两次查询中间有其它事务插入数据,就会产生幻读。
那么MySQL是如何避免幻读?
- 在快照读情况下,MySQL通过
mvcc
来避免幻读。 - 在当前读情况下,MySQL通过
next-key
来避免幻读(记录锁和间隙锁来实现的)。
next-key包括两部分:行锁和间隙锁。行锁是加在索引上的锁,间隙锁是加在索引之间的。
Serializable
隔离级别也可以避免幻读,会锁住整张表,并发性极低,一般不会使用。
作者:江西陈胖子
链接:https://www.nowcoder.com/discuss/469540317159563264?sourceSSR=search
来源:牛客网
作者:江西陈胖子
链接:https://www.nowcoder.com/discuss/469540317159563264?sourceSSR=search
来源:牛客网
当前读
4. 日志
bin log
(二进制日志)和 redo log
(重做日志)和 undo log
(回滚日志)。
bin log
bin log
是MySQL数据库级别的文件,记录对MySQL数据库执行修改的所有操作,不会记录select和show语句,主要用于恢复数据库和同步数据库。
MySQL binlog 以事件形式记录,还包含语句所执行的消耗的时间,MySQL 的二进制日志是事务安全型的。binlog 的主要目的是复制和恢复。
binlog 有三种格式,各有优缺点:
- statement: 基于 SQL 语句的模式,某些语句和函数如 UUID, LOAD DATA INFILE 等在复制过程可能导致数据不一致甚至出错。
- row: 基于行的模式,记录的是行的变化,很安全。但是 binlog 会比其他两种模式大很多,在一些大表中清除大量数据时在 binlog 中会生成很多条语句,可能导致从库延迟变大。
- mixed: 混合模式,根据语句来选用是 statement 还是 row 模式。
redo log
redo log
是innodb引擎级别,用来记录innodb存储引擎的事务日志,不管事务是否提交都会记录下来,用于数据恢复。当数据库发生故障,innoDB存储引擎会使用redo log
恢复到发生故障前的时刻,以此来保证数据的完整性
undo log
除了记录redo log
外,当进行数据修改时还会记录undo log
,undo log
用于数据的撤回操作,它保留了记录修改前的内容。通过undo log
可以实现事务回滚,并且可以根据undo log
回溯到某个特定的版本的数据,实现MVCC。
bin log和redo log有什么区别?
-
bin log
会记录所有日志记录,包括InnoDB、MyISAM等存储引擎的日志;redo log
只记录innoDB自身的事务日志。 -
bin log
只在事务提交前写入到磁盘,一个事务只写一次;而在事务进行过程,会有redo log
不断写入磁盘。 -
bin log
是逻辑日志,记录的是SQL语句的原始逻辑;redo log
是物理日志,记录的是在某个数据页上做了什么修改链接:https://www.nowcoder.com/discuss/469540317159563264?sourceSSR=search
来源:牛客网
MySQL - 一条 SQL 的执行过程详解 - kisshappyboy - 博客园 (cnblogs.com)
深分页怎么优化
select * from xxx where id > start_id order by id limit 10;
通过主键索引,每次定位到start_id的位置,然后往后遍历10个数据,这样不管数据多大,查询性能都较为稳
执行顺序:from --> where -- > group by --> having --> select --> order by --> limit
sql 面试题
精选数据库“事务“ 常见19道面试题!面试前冲刺-CSDN博客
[javapass](http://www.javapass.cn/#/_分库分表之后,id 主键如何处理?)
Mysql基础知识点 | 鲁大猿 (jiagoujishu.cn)
2. redis
缓存穿透
布隆过滤器BloomFilter概念、原理、实现 - 大数据从业者FelixZh - 博客园 (cnblogs.com)
缓存的常见删除策略有哪些?
常见的删除策略有以下3种:
\1. 定时删除
在设置键的过期时间的同时,创建一个定时器,让定时器在键的过期时间来临时,立即执行对键的删除操
作。
\2. 惰性删除
放任过期键不管,每次从键空间中获取键时,检查该键是否过期,如果过期,就删除该键,如果没有过期, 就返回该键。
\3. 定期删除
每隔一段时间,程序对数据库进行一次检查,删除里面的过期键,至于要删除哪些过期键,则由算法决定。
其中定时删除和定期删除为主动****删除策略,惰性删除为被动****删除策略。
接下来我们一一讲解:
定时删除策略
定时删除策略通过使用定时器,定时删除策略可以保证过期键尽可能快地被删除,并释放过期键占用的内存。
因此,定时删除策略的优缺点如下所示:
\1. 优点:对内存非常友好
\2. 缺点:对CPU时间非常不友好
举个例子,如果有大量的命令请求等待服务器处理,并且服务器当前不缺少内存,如果服务器将大量的CPU时间 用来删除过期键,那么服务器的响应时间和吞吐量就会受到影响。
也就是说,如果服务器创建大量的定时器,服务器处理命令请求的性能就会降低, 因此Redis目前并没有使用定时删除策略。
惰性删除策略
惰性删除策略只会在获取键时才对键进行过期检查,不会在删除其它无关的过期键花费过多的CPU时间。
因此,惰性删除策略的优缺点如下所示:
\1. 优点:对CPU时间非常友好
\2. 缺点:对内存非常不友好
举个例子,如果数据库有很多的过期键,而这些过期键又恰好一直没有被访问到,那这些过期键就会一直占用着宝贵的内存资源,造成资源浪费。
定期删除策略
定期删除策略是定时删除策略和惰性删除策略的一种整合折中方案。
定期删除策略每隔一段时间执行一次删除过期键操作,并通过限制删除操作执行的时长和频率来减少删除操作对 CPU时间的影响,同时,通过定期删除过期键,也有效地减少了因为过期键而带来的内存浪
Redis 事务有哪些特性?
- Redis 事务中的所有命令都会存放在队列中按序执行。
- Redis 事务中的所有命令在没有提交(exec)之前,都不会执行,所以也就不存在关系型数据库中经常出现的脏读,不可重复读,幻读等并发操作的问题。
- Redis 事务不保证原子性,命令如果本身的语法没有问题,只是在执行的过程中出错,不影响其他命令的执行。
原文链接:https://blog.csdn.net/u012206617/article/details/89002161
redis 和msyql 数据一致性
如何保障MySQL和Redis的数据一致性? | 二哥的Java进阶之路 (javabetter.cn)
Redis与DB的数据一致性解决方案(史上最全) - 疯狂创客圈 - 博客园 (cnblogs.com)
面试题总结——Redis_redission面试题-CSDN博客
3. spring
java 集合篇
arrayList
Collection - ArrayList 源码解析 | Java 全栈知识体系 (pdai.tech)
ArrayList实现了List接口,是顺序容器,即元素存放的数据与放进去的顺序相同,允许放入null
元素,底层通过数组实现**
size(), isEmpty(), get(), set()方法均能在常数时间内完成,add()方法的时间开销跟插入位置有关,addAll()方法的时间开销跟添加元素的个数成正比
ArrayList没有实现同步(synchronized),如果需要多个线程并发访问,用户可以手动同步,也可使用Vector替代。
扩容机制:数组扩容通过一个公开的方法ensureCapacity(int minCapacity)来实现。
扩容操作最终是通过grow()
方法完成的。
LinkedList
Collection - LinkedList源码解析 | Java 全栈知识体系 (pdai.tech)
LinkedList同时实现了List接口和Deque接口,也就是说它既可以看作一个顺序容器,又可以看作一个队列(Queue),同时又可以看作一个栈(Stack)LinkedList没有实现同步(synchronized)