数据库

270 阅读8分钟

1. 索引

1、为什么要使用索引

2、什么样的信息能成于索引

主键、唯一键、普通键

3、索引的数据结构

二叉 查找数进行二分查找

B- TREE

B+ TREE

HASH

4、密集索引和稀疏索引的区别

密集索引:叶子节点不仅仅保存的键值,还保存位于同一行记录里的其他列信息。

稀疏索引:叶子节点仅保存键位信息和该行数据的地址,有的稀疏索引仅保存键位信息和主键。(二次查找)

由于密集索引决定了表的物理排列顺序,一个表只能有一个物理排列顺序,所以一个表只能创建一个密集索引。

myisam所有都是稀疏索引,innodb有且仅有一个密集索引。

innodb定义密集索引规则:

1、有主键,主键为密集索引

2、无主键、第一个唯一非空索引为密集索引

3、都没有,内部会生成一个隐藏主键

非主键索引存储相关键位信息和其对应的主键值,包含两次查找。

5、如何定位并优化慢查询sql

根据慢日志定位慢查询sql

slow_query_log_file xxx

slow_query_log on

long_query_time 1

show status like '%slow_queries%' 慢sql次数

set global slow_query_log= on; 打开慢日志

使用explain工具分析sql

type (index、all表明走的是全表扫描需优化)

extra(Using filesort【文件排序】 Using temporary【需要用到临时表】 需要优化)

一般保证查询达到range级别,最好达到ref。

修改sql或者尽量让sql走索引

6、联合索引的最左匹配原则成因

mysql会一直向右匹配直到遇到范围查询(> < between like )就停止匹配

a_b a= and b= a= 走 b= 不走

7、索引是创建的越多越好吗?

数据量小的表不需要建立索引,建立会增加额外的索引开销;数据变更需要维护索引,意味着需要索引建的越多需要更多的维护成本。

7、索引的一些潜规则

覆盖索引:

回表:

索引下推:

最左匹配:

2. MyISAM和Innodb关于锁方面的区别是什么?

前者默认表级锁,不支持行级锁。

后者默认行级锁,也支持表级锁

怎么显示给表加锁?

lock tables xxx(tableName) read(write)

unlock tables (释放锁)

读锁也叫共享锁

写锁也叫排他锁(sql语句后加上for update 显示加上排他锁)

先上读锁,再写,会block住

先上读锁,再读,不会block住

先上写锁,再读,会block住

先上写锁,再写,会block住

在rc隔离级别下,mysql只会对查询到的数据进行加锁。

Innodb默认自动提交事务

show variables like 'autocommit'

set autocommit=0 //关闭自动提交事务,只针对当前会话

lock in share mode 读锁

表级锁和索引无关,innodb在sql没有用到索引的时候走的是表级锁,用到索引走的是行级锁和gap锁。

myisam:

  • 频繁执行全表count的语句

  • 对数据增删改的频率不高,查询非常频繁

  • 没有事务

innodb:

  • 数据增删改查都相当频繁

  • 可靠性要求比较高,要求支持事务

3. 数据库事务的四大特性?

ACID

原子性

一致性

隔离性

持久性

事务隔离级别以及各级别下的并发访问问题

事务并发访问引起的问题以及如何避免

事务隔离级别更新丢失脏读不可重复读幻读
未提交读避免发生发生发生
已提交读避免避免发生发生
可重复读避免避免避免发生
串行化避免避免避免避免

mysql innodb默认隔离级别 可重复读

orcale 默认隔离级别 已提交读

Innodb可重复读隔离级别下如何避免幻读

表现:快照读(非阻塞读) 伪mvcc

内在:next-key 锁(行锁+gap锁)

4. 数据库语法部分

group by

group by 里出现某个表的字段,select里面的列要么是group by里面出现的列,要么是别的表的列,要么是带函数的列。

having

通常和group by 一起执行

where过滤行,having过滤组

出现在同一sql的顺序:where>group by >having

sum、count、max、min、avg

5. 数据库分库发表

  • 为什么要分库分表?

分库分表一定是为了支撑高并发、数据量大两个问题

  • 用过哪些分库分表中间件?不同的分库分表中间件都有什么优点和缺点?

比较常见的包括:cobar、TDDL、atlas、sharding-jdbc、mycat

cobar:阿里b2b团队开发和开源的,属于proxy层方案。早些年还可以用,但是最近几年都没更新了,基本没啥人用,差不多算是被抛弃的状态吧。而且不支持读写分离、存储过程、跨库join和分页等操作。

TDDL:淘宝团队开发的,属于client层方案。不支持join、多表查询等语法,就是基本的crud语法是ok,但是支持读写分离。目前使用的也不多,因为还依赖淘宝的diamond配置管理系统。

atlas:360开源的,属于proxy层方案,以前是有一些公司在用的,但是确实有一个很大的问题就是社区最新的维护都在5年前了。所以,现在用的公司基本也很少了。

sharding-jdbc:当当开源的,属于client层方案。确实之前用的还比较多一些,因为SQL语法支持也比较多,没有太多限制,而且目前推出到了2.0版本,支持分库分表、读写分离、分布式id生成、柔性事务(最大努力送达型事务、TCC事务)。而且确实之前使用的公司会比较多一些(这个在官网有登记使用的公司,可以看到从2017年一直到现在,是不少公司在用的),目前社区也还一直在开发和维护,还算是比较活跃,个人认为算是一个现在也可以选择的方案。

mycat:基于cobar改造的,属于proxy层方案,支持的功能非常完善,而且目前应该是非常火的而且不断流行的数据库中间件,社区很活跃,也有一些公司开始在用了。但是确实相比于sharding jdbc来说,年轻一些,经历的锤炼少一些。

所以综上所述,现在其实建议考量的,就是sharding-jdbc和mycat,这两个都可以去考虑使用。

sharding-jdbc这种client层方案的优点在于不用部署,运维成本低,不需要代理层的二次转发请求,性能很高,但是如果遇到升级啥的需要各个系统都重新升级版本再发布,各个系统都需要耦合sharding-jdbc的依赖;

mycat这种proxy层方案的缺点在于需要部署,自己及运维一套中间件,运维成本高,但是好处在于对于各个项目是透明的,如果遇到升级之类的都是自己中间件那里搞就行了。

通常来说,这两个方案其实都可以选用,但是我个人建议中小型公司选用sharding-jdbc,client层方案轻便,而且维护成本低,不需要额外增派人手,而且中小型公司系统复杂度会低一些,项目也没那么多;

但是中大型公司最好还是选用mycat这类proxy层方案,因为可能大公司系统和项目非常多,团队很大,人员充足,那么最好是专门弄个人来研究和维护mycat,然后大量项目直接透明使用即可。

我们,数据库中间件都是自研的,也用过proxy层,后来也用过client层

  • 你们具体是如何对数据库如何进行垂直拆分或水平拆分的?

水平拆分的意思,就是把一个表的数据给弄到多个库的多个表里去,但是每个库的表结构都一样,只不过每个库表放的数据是不同的,所有库表的数据加起来就是全部数据。水平拆分的意义,就是将数据均匀放更多的库里,然后用多个库来抗更高的并发,还有就是用多个库的存储容量来进行扩容。

垂直拆分的意思,就是把一个有很多字段的表给拆分成多个表,或者是多个库上去。每个库表的结构都不一样,每个库表都包含部分字段。一般来说,会将较少的访问频率很高的字段放到一个表里去,然后将较多的访问频率很低的字段放到另外一个表里去。因为数据库是有缓存的,你访问频率高的行字段越少,就可以在缓存里缓存更多的行,性能就越好。这个一般在表层面做的较多一些。

  • 如何系统平滑地迁移到分库分表上面去

1、停机迁移方案

2、双写迁移方案

  • 如何设计可以动态扩容缩容的分库分表方案?

  • 分库分表之后,id主键如何处理?

1、数据库自增id

2、snowflake算法

  • 如何实现mysql的读写分离?

其实很简单,就是基于主从复制架构,简单来说,就搞一个主库,挂多个从库,然后我们就单单只是写主库,然后主库会自动把数据给同步到从库上去。

  • MySQL主从复制原理的是啥?

主库将变更写binlog日志,然后从库连接到主库之后,从库有一个IO线程,将主库的binlog日志拷贝到自己本地,写入一个中继日志中。接着从库中有一个SQL线程会从中继日志读取binlog,然后执行binlog日志中的内容,也就是在自己本地再次执行一遍SQL,这样就可以保证自己跟主库的数据是一样的。

这里有一个非常重要的一点,就是从库同步主库数据的过程是串行化的,也就是说主库上并行的操作,在从库上会串行执行。所以这就是一个非常重要的点了,由于从库从主库拷贝日志以及串行执行SQL的特点,在高并发场景下,从库的数据一定会比主库慢一些,是有延时的。所以经常出现,刚写入主库的数据可能是读不到的,要过几十毫秒,甚至几百毫秒才能读取到。

而且这里还有另外一个问题,就是如果主库突然宕机,然后恰好数据还没同步到从库,那么有些数据可能在从库上是没有的,有些数据可能就丢失了。

所以mysql实际上在这一块有两个机制,一个是半同步复制,用来解决主库数据丢失问题;一个是并行复制,用来解决主从同步延时问题。

这个所谓半同步复制,semi-sync复制,指的就是主库写入binlog日志之后,就会将强制此时立即将数据同步到从库,从库将日志写入自己本地的relay log之后,接着会返回一个ack给主库,主库接收到至少一个从库的ack之后才会认为写操作完成了。

所谓并行复制,指的是从库开启多个线程,并行读取relay log中不同库的日志,然后并行重放不同库的日志,这是库级别的并行。

  • bin log和relay log

bin log

  • 二进制文件
  • binlog在mysql的server层实现(引擎其用)
  • binlog是逻辑日志,记录的是一条语句的原始逻辑。
  • binlog不限大小,追加写入,不会覆盖之前的日志