大厂面试题详解五:数据库Mysql篇

336 阅读4分钟

​索引类型,实现原理

B+树:左边小,右边大,只有叶子节点包含key和数据 ,同时叶子节点有链指针,方便区间查询数据。好处是减小节点大小,降低磁盘IO。Innodb引擎下数据文件本身就是索引文件

聚簇索引:叶子节点就是数据节点

非聚簇索引:非聚簇索引的叶子节点仍然是索引节点,只不过有指向对应数据块的指针

覆盖索引:指一个查询语句的数据只用从索引中就能获得,不必从数据库表中获取

读写分离

同步

从库开一个线程主动从主库拉取日志保存到本地(relay_log),再单独开一个线程从relay日志保存到本地

半同步

主库写入binlog后强制同步日志到从库,从库写入日志成功后返回ACK确认给主库,主库收到至少一个从库的确认才认为写操作完成(防止主库宕机导致数据丢失)

主从延迟解决方案

分库,主库拆分,降低主库的写并发

设置强制走主库查询

事务的基本特性,隔离级别

ACID:原子性、一致性、持久性、隔离性

怎么保证ACID

原子性:undo log保证,事务回滚撤销已经执行成功的sql

一致性:代码层面判断

持久性:redo log保证 内存+redo log,宕机从redo log恢复写入磁盘

隔离性:MVCC

MVCC、隔离级别

1、read uncommit(读未提交) 读到其他事务未提交的数据 脏读

2、read commit(读已提交) 两次读取结果不一致 不可重复读

3、repeatable read(可重复复读)mysql 默认级,每次读取结果都一样 幻读

实现原理:MVCC 多版本并发控制,行数据隐藏了两列创建事务id,删除事务id,查询只会查询创建时间事务id<当前事务id的行,所有能保证每次读取的数据是一样的,但是插入或者删除数据并且同时在做范围查询的时候无法保证

幻读条件:做查询,其他事务做了insert或者delete,必须是一个范围。同样的查询条件查询到不同的结果

4、serializable 串行

锁的类型,原理

表锁 :alter修改表等操作

行锁:

1、for update 悲观锁 排他锁

2、version版本乐观锁

3、lock in share mode 共享锁 读锁,只能读不能写

4、页锁

数据库优化从哪些方面

where条件具体

where条件及排序使用索引

避免在where条件进行null判断 is null

避免在where条件中使用or连接条件

避免在where条件中使用in not in 对于连续值使用between

避免like'%%'

避免在条件中使用表达式

避免在条件中使用函数

避免索引过多,不必要的索引不要

尽可能避免更新索引列数据

避免使用force_index

分库分表

顺序:先垂直、后水平

垂直拆分

垂直分表

大表拆小表,基于字段进行。一般表中字段较多,将不常用的、数据较大、长度较长的拆分到扩展表

垂直分库

针对系统中不同业务拆分,比如用户、商品、订单,垂直的维度现在基本不用考虑了,因为微服务已经是在做这样一件事情了。

水平拆分

针对数据量巨大的表,根据range、hash等某种规则拆分到多张表

  1. RANGE

  2. 从id 0-1000一张表,1001-2000一张表

  3. HASH取摸

  4. 如用户id hash取模,分配到不同数据库

  5. 地理位置

  6. 时间

  7. 历史数据归档,比如半年前数据归档

一般来说都是基于hash取模的方式来做分表,再加上定期的数据归档来达到目标。

分表后非sharding_key字段查询

在分表之后,我们的查询理论上所有的查询都需要根据sharding_key去查询数据,比如订单表根据用户id作为sharding_key分表,那么针对C端的场景查询都是基于用户id维度的这个很好办,但是对于B端需要根据商户或者其他维度的查询怎么解决?

1、落两份数据,走不同库查询,针对B端和C端的场景区分开

2、关联表,针对其他场景的字段做关联关系,先从中间表查询。这个方式其实在设计数据库的时候可以通过表的设计来做到,不过业务太复杂的话也是不好处理的。

3、索引、多线程扫全表。需要的字段建好索引,去扫全表的话针对B端的场景也是可以接受的

4、数仓,数据库不是很大的话,一般的离线数仓其实也可以作为准实时的来用,就是价格贵就是了。业务不是很大的公司效果其实还可以接受。