面试题:数据库MySQL

存储引擎MyISAM和InnoDB区别

  • MyISAM是Mysql5.5默认的数据库引擎
  • InnoDB是Mysql5.5以后引入的默认引擎
  • MyISAM只有表级锁;InnoDB支持行级锁和表级锁(默认是行级锁)
  • MyISAM强调性能,不支持事务,最大的缺陷是崩溃后无法安全恢复;InnoDB支持事务、外键、回滚、崩溃回滚等功能(假如项目是读密集的话,也可以采用MyISAM的,只要不害怕崩溃恢复问题)
  • MyISAM不支持外键;InnoDB支持外键
  • MyISAM不支持MVCC(多版本并发控制);InnoDB支持MVCC

多版本控制MVCC:

  • 多版本控制指的是一种提高并发的技术。
  • 最早的数据库系统,只有读读之间可以并发,读写,写读,写写都要阻塞。
  • 引入多版本之后,只有写写之间相互阻塞,其他三种操作都可以并行,这样大幅度提高了InnoDB的并发度。
  • 参考https://segmentfault.com/a/1190000012650596

索引

  • MySQL的索引主要有BTree索引和哈希索引
  • 哈希索引的底层数据结构就是哈希表,单条件查询的时候,可以算则哈希索引,查询速度快;其它大部分查询,可以选择BTree索引,BTree索引使用B树中的B+Tree作为数据库
  • MyISAM中的BTree索引:叶子节点中的data域存放的是数据记录的地址。在检索索引的时候,首先按照B+Tree搜索算法搜索索引,如果指定的Key存在,那么取出data的值,然后按照data中的地址去读取相应数据,这称为“非聚簇索引”
  • InnoDB中的BTree索引:InnoDB中数据文件本身就是索引文件,MyISAM中的索引文件和数据文件是分离的;InnoDB中树的叶子结点保存了完整的数据记录,索引的Key就是数据表的主键,因此InnoDB表数据文件本身就是主索引,这被称为“聚簇索引”,其他的索引是辅助索引,辅助索引的data域存放相应记录的主键的值而不是地址。当使用辅助索引时,首先在辅助索引树中查找到主键值,再到主键索引树中查找数据

查询缓存

  • 执行查询语句的时候,会先查询缓存
  • MySQL8.0后取消,因为不太实用

事务四大特性

  • 原子性(Atomic):一个事务中的操作,要么一起执行,要么不执行
  • 一致性(Consistency):事务执行后,数据库的一致性约束没有被破坏,比如转账中账户扣除款项后必须给另一个账户加上款项
  • 隔离性(Isolation):两个并发事务互不干扰
  • 持久性(Durability):事务完成后,事务操作的数据会持久化存储

并发事务带来的问题

  • 脏读:一个事物正在修改数据,数据还没提交就被另一个事务访问了
  • 丢失修改:两个事务同时修改数据,那么会有一个事务提交的修改丢失了
  • 不可重复读:一个事务多次访问一个数据,结果不一致
  • 幻读:与不可重复读类似,主要是一个事务在读取时,另一个事务插入/删除了数据,那么造成前一个事务后面读取到了原来不存在的数据(或者原来读到的现在读不到了)

事务隔离级别

  • 读取未提交:最低隔离级别,导致脏读、不可重复、读幻读
  • 读取已提交:允许读取已经提交的数据,阻止脏读,导致不可重复、读幻读
  • 可重复读:同一字段多次读取的结果一致,阻止脏读、不可重复读,导致幻读
  • 可串行化,最高隔离级别,服从ACID,所有事物依次逐个执行,防止脏读、不可重复读、幻读
  • InnoDB默认可重复读隔离级别,在分布式事务情况下,一般采用可串行化级别

锁机制与InnoDB锁算法

  • 表级锁:粒度最大的一种,对整张表进行加锁,锁冲突概率高,并发度低,实现简单,资源消耗小,加锁快
  • 行级锁:粒度最小的一种,对当前操作行加锁,锁冲突概率低,并发度高,实现复杂,资源消耗大,加锁慢
  • 共享锁(S):读锁
  • 排他锁(X):写锁
  • 意向共享锁(IS):当要访问的数据被排他锁锁住时,可以加一个意向共享锁,可以加多个,表级锁
  • 意向排他锁(IX):当要访问的数据被锁住的时候,可以加一个意向排他锁,仅可以加一个,表级锁
  • InnoDB存储引擎的锁算法:
  1. Record lock:单个行记录上的锁
  2. Gap lock:间隙锁,锁定一个范围,不包括记录本身
  3. Next-key lock:record + gap,锁定一个范围,包括记录本身
  • InnoDB在行查询的时候使用Next-key
  • Next-key lock能解决幻读问题
  • 查询的条件中使用索引单一主键时,Next-key降为Record
  • Gap设计的目的是为了阻止多个事务将记录插入同一个范围之内,因为这会导致幻读
  • 两种方式关闭Gap
  1. 将事务隔离级别设置为RC
  2. 将参数nonodb_locks_unsafe_for_binlog设定为1

大表优化

  • 单表中数据过大时,CRUD性能会下降,需要优化:
  • 限定数据范围:禁止不带限制的查询语句
  • 读/写分离操作:主库写,从库读
  • 垂直分区:按照数据表的相关性进行拆分(拆分属性,但是拆的不好就破坏了第一范式),尽量做到小表
  • 水平分区:保持表结构不变,将数据分散到不同的表或者库中

分库分表后id主键如何处理

  • 没有分库的时候,表的主键从1开始累加,但是分库分表以后,需要全局id,如下方式生成全局id:
  • UUID:不适合做主键,因为太长了,且无序不可读,查询效率低,比较适合用于生成唯一名字的标识,比如文件名
  • 数据库自增id:两台数据库设置不同步长,使用不同策略生成,但是需要独立部署 
  • 利用redis生成:灵活性能好,不依赖数据库,但是引入新组件redis后复杂
  • snowflake雪花算法:
  • 美团Leaf分布式ID生态系统:

池化设计思想,数据库连接池

  • 池化不单在数据库中使用,java线程池、jdbc连接池、redis连接池等等
  • 数据库连接本质是一个Socket连接
  • 数据库服务端需要维护缓存和用户权限信息,需要占用一些内存
  • 将数据库连接池看做是维护数据库连接的缓存,后面需要连接数据库时可以重新使用这些连接
  • 每次用户使用数据库,都要打开和维护数据库连接的话,消耗资源
  • 在连接池中,创建连接后,将其放置在池中,每次使用时直接用就行,不需要重新建立新的链接,也能减少用户等待时间

一条SQL语句如何在MySql中执行

  1. 连接器:主要用于身份验证和权限认证,用户账户登录成功后去权限表中查询权限
  2. 查询缓存:MySQL8.0后移出,执行查询的时候先查询缓存,缓存中以Key-Value存储,如果Key命中,直接返回Value
  3. 分析器:分为词法分析和语法分析。词法分析主要是提取关键字,比如字段名、表名、select等;语法分析是判断输入的sql语句是否正确,是否符合语法
  4. 优化器:使用优化器认为最优的方案去执行操作,当然,不一定是最优的,只能是优化器自己认为最优,比如多个索引的时候如何选择索引、多表查询时如何关联顺序
  5. 执行器:选择了优化器的执行方案后,就准备执行,执行前会检验用户有没有权限,然后再调用引擎的接口
  • 查询语句执行流程
  1. 查询语句权限,如果没有权限,返回错误信息;
  2. 如果有权限,先查询缓存(8.0后不查询)
  3. 通过分析器进行词法分析,提取关键字,判断是否有语法错误
  4. 优化器确定执行方案
  5. 进行权限校验,没有权限就返回错误信息,有权限就调用数据库引擎接口,返回引擎执行结果
  • 更新语句执行流程(InnoDB引擎):update tb_student A set A.age='19' where A.name=' 张三 ';
  1. 先查询张三这条数据,如果有缓存,也会使用缓存
  2. 拿到查询的语句,将其age改为19,然后调用引擎API接口,写入数据
  3. InnoDB引擎将数据保存在内存中,同时记录redo log日志,此时redo log进入prepare状态,然后告诉执行器,执行完成了,随时可以提交
  4. 执行器收到通知后记录binlog,然后调用引擎接口,提交redo log为提交状态
  5. 更新完成
  6. 所以其实使用的是两阶段提交
  • 为什么更新时使用两个日志模块
  1. 最初MySql没有InnoDB引擎,只有MyISAM引擎,所以之前是没有crash-safe数据库异常崩溃提交记录不消失功能(binlog只能用来归档)
  2. 并不是说一个日志模块不可以,只是InnoDB引擎通过redo log来支持事务
  3. 使用两阶段提交,保证不会因为两个日志的提交顺序造成问题

一条SQL语句执行得很慢的原因有哪些?

  • 分为两种情况,一种是大多数情况是正常的,只是偶尔会出现很慢的情况;第二种是在数据量不变的情况下,语句一直都很慢
  •  
  • 针对偶尔很慢:数据库在刷新脏页;拿不到锁
  • 刷新脏页,数据库数据更新好,不会马上同步到磁盘中,而是将更新记录写到redo log中,等到空闲时在同步到磁盘中
  1. redo log写满了,只能暂停其他操作,先同步数据到磁盘中,这时候就会导致SQL执行得很慢
  2. 内存不够用了,如果一次查询的数据较多,恰好所查的页不在内存中,需要申请内存空间存储数据页,此时刚好内存不够了,那么需要淘汰内存数据页,如果是干净页,直接淘汰就可以了,如果恰好是脏页那么需要刷新脏页以后才能淘汰
  • 拿不到锁,此时只能等了,没办法
  •  
  • 针对一直很慢,就要好好考虑SQL语句了,分几种情况:
  1. 字段上没有索引,只能全表扫描
  2. 字段上有索引,但是却没有用上,比如在索引字段使用了运算符、函数等
  3. 使用其他索引而不是主键索引,要遍历两次索引树

高质量SQL建议

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值