目录
概括 :
优化
如何定位慢查询
慢查询出现原因 :
-
聚合查询
-
多表查询
-
表数据量过大查询
-
深度分页查询
表现 :
-
页面加载过慢,接口压测响应时间过长 (超过1s) ;
方案一 :
使用开源工具 :
-
调试工具 : Arthas ;
-
运维工具 : Prometheus , Skywalking ;
方案二 :
MySql自带慢日志 :
将执行慢的SQl语句存到日志文件当中 :
答案 :
嗯~,我们当时做压测的时候有的接口非常的慢,接口的响应时间超过了2秒以上,因为我们当时的系统部署了运维的监控系统Skywalking ,在展示的报表中可以看到是哪一个接口比较慢,并且可以分析这个接口哪部分比较慢,这里可以看到SQL的具体的执行时间,所以可以定位是哪个sql出了问题
如果,项目中没有这种运维的监控系统,其实在MySQL中也提供了慢日志查询的功能,可以在MySQL的系统配置文件中开启这个慢日志的功能,并且也可以设置SQL执行超过多少时间来记录到一个日志文件中,我记得上一个项目配置的是2秒,只要SQL执行的时间超过了2秒就会记录到日志文件中,我们就可以在日志文件找到执行比较慢的SQL了。
SQl执行很慢,如何优化
-
聚合查询 : 尝试新增一个临时表 ;
-
多表查询 : 尝试优化SQl语句的结构 ;
-
表数据量过大 : 添加索引 ;
SQl执行计划 :
可以采用EXPLAIN 或者 DESC 命令获取MySQL如何执行SELECT语句的信息 :
语法 :
- 直接在select 语句之前加上关键字 explain / desc
EXPLAIN select 字段列表 FROM 表名 WHERE 条件 ;
例 :
分析 :
-
possible_key 当前sql可能会使用到的索引
-
key 当前sql实际命中的索引
-
key_len 索引占用的大小
-
Extra 额外的优化建议
Extra | 含义 |
---|---|
Using where; Using Index | 查找使用了索引,需要的数据都在索引列中能找到,不需要回表查询数据 |
Using index condition | 查找使用了索引,但是需要回表查询数据 |
type : 这条sql的连接的类型,性能由好到差为NULL、system、const、eq_ref、ref、range、 index、all ;
-
system:查询系统中的表
-
const:根据主键查询
-
eq_ref:主键索引查询或唯一索引查询
-
ref:索引查询
-
range:范围查询
-
index:索引树扫描
-
all:全盘扫描
如果使index或者all,就需要进行优化了 ;
如何分析 :
可以采用MySQL自带的分析工具 EXPLAIN
-
通过key和key_len检查是否命中了索引(索引本身存在是否有失效的情况)
-
通过type字段查看sql是否有进一步的优化空间,是否存在全索引扫描或全盘扫描;
-
通过extra建议判断,是否出现了回表的情况,如果出现了,可以尝试添加索引或修改返回字段来修复
面试官:那这个SQL语句执行很慢, 如何分析呢?
候选人:如果一条sql执行很慢的话,我们通常会使用mysql自动的执行计划explain来去查看这条sql的执行情况,比如在这里面可以通过key和key_len检查是否命中了索引,如果本身已经添加了索引,也可以判断索引是否有失效的情况,第二个,可以通过type字段查看sql是否有进一步的优化空间,是否存在全索引扫描或全盘扫描,第三个可以通过extra建议来判断,是否出现了回表的情况,如果出现了,可以尝试添加索引或修改返回字段来修复
索引概念以及底层数据结构
索引(index)是帮助MySQl高效获取数据的数据结构(有序)。在数据之外,数据库系统还维护了满足特定查找算法的数据结构(B+树),这些数据结构以某种方式引用(指向)数据,这样就可以在这些数据结构上实现高级查找算法,这种数据结构就是索引 ;
作用 :
-
索引(index)是帮助MySQl高效获取数据的数据结构;
-
提高数据检索的效率,降低数据库io的压力 ;
-
通过索引能够对数据进行排序 ,降低数据排序的成本,降低了CPU的消耗 ;
面试官:了解过索引吗?(什么是索引)
候选人:嗯,索引在项目中还是比较常见的,它是帮助MySQL高效获取数据的数据结构,主要是用来提高数据检索的效率,降低数据库的IO成本,同时通过索引列对数据进行排序,降低数据排序的成本,也能降低了CPU的消耗 ;
面试官:索引的底层数据结构了解过嘛 ?
候选人:MySQL的默认的存储引擎InnoDB采用的B+树的数据结构来存储索引,选择B+树的主要的原因是:
-
阶数更多,路径更短 ,是一个矮胖树 ;
-
磁盘读写代价B+树更低,非叶子节点只存储指针,叶子阶段存储数据,
-
第三是B+树便于扫库和区间查询,叶子节点是一个双向链表 ;
对比B树 :
-
非叶子结点不存储数据,只存储指针 ,只有在叶子结点上才会存储数据 ;
-
B+树的磁盘读写代价更低 ;
-
查询效率B+树更加稳定 ;
-
B+树便于扫库和区间查询 ;
面试官:B树和B+树的区别是什么呢?
候选人:第一:在B树中,非叶子节点和叶子节点都会存放数据,而B+树的所有的数据都会出现在叶子节点,在查询的时候,B+树查找效率更加稳定
第二:在进行范围查询的时候,B+树效率更高,因为B+树都在叶子节点存储,并且叶子节点是一个双向链表
什么是聚簇索引什么是非聚簇索引
聚集索引选取规则
-
如果存在主键,主键索引就是聚集索引
-
如果不存在主键,将使用第一个唯一(UNIQUE)索引作为聚集索引 ;
-
如果没有主键,或没有合适的唯一索引,则InnoDB会自动生成一个rowId作为隐藏的聚集索引 ;
回表查询
引用上表;
给出如下查询语句 :
select * from user where name = 'Arm' ;
-
先根据name字段使用name索引,查出Arm对应的id ;
-
再根据id回表使用id索引查询数据 ;
也就是 :
-
先根据二级索引查询得到主键 ;
-
再根据聚集索引查询表得到完整数据 ;
如果只是查询主键才不会回表 ;
面试官:什么是聚簇索引什么是非聚簇索引 ?
候选人:
好的~,聚簇索引主要是指数据与索引放到一块,B+树的叶子节点保存了整行数据,有且只有一个,一般情况下主键在作为聚簇索引的;
非聚簇索引值的是数据与索引分开存储,B+树的叶子节点保存对应的主键,可以有多个,一般我们自己定义的索引都是非聚簇索引;
面试官:知道什么是回表查询嘛 ?
候选人:嗯,其实跟刚才介绍的聚簇索引和非聚簇索引是有关系的,回表的意思就是通过二级索引找到对应的主键值,然后再通过主键值找到聚集索引中所对应的整行数据,这个过程就是回表
【备注:如果面试官直接问回表,则需要先介绍聚簇索引和非聚簇索引】
覆盖索引
覆盖索引指查询使用了索引,并且需要返回的列,在该索引中全部能够找到 ;
也即是索引覆盖了查询条件 ;
其中
-
1,2条是覆盖索引 ;
-
第三条需要回表查询 ;
面试官:知道什么叫覆盖索引嘛 ?
候选人:嗯~,清楚的
-
覆盖索引是指select查询语句使用了索引,在返回的列,必须在索引中全部能够找到,如果我们使用id查询,它会直接走聚集索引查询,一次索引扫描,直接返回数据,性能高。
-
如果按照二级索引查询数据的时候,返回的列中没有创建索引,有可能会触发回表查询,尽量避免使用select *,尽量在返回的列中都包含添加索引的字段;
MySql超大分页
在数据量比较大时,如果进行limit分页查询,在查询时,越往后,分页查询效率越低 ;
优化思路 :
-
一般分页查询的时候,通过创建覆盖索引能够比较好地提高性能 ;
-
可以通过覆盖索引加子查询形式进行优化 ;
面试官:MYSQL超大分页怎么处理 ?
候选人:嗯,超大分页一般都是在数据量比较大时,我们使用了limit分页查询,并且需要对数据进行排序,这个时候效率就很低,我们可以采用覆盖索引和子查询来解决
先分页查询数据的id字段,确定了id之后,再用子查询来过滤,只查询这个id列表中的数据就可以了
因为查询id的时候,走的覆盖索引,所以效率可以提升很多
索引创建原则
-
先陈述自己在实际工作中是怎么用的 ;
-
主键索引 ;
-
唯一索引 ;
-
根据业务创建地索引(复合索引) ;
原则 :
-
针对数据量比较大,且查询比较频繁的表建立索引 。单表超过10w条记录(增加用户体验) ;
-
针对于常用作为查询的条件(where),排序,分组(group by)操作的字段建立索引 ;
-
尽量选取区分度高的列作为索引,尽量建立唯一索引,区分度越高,使用索引的效率越高 ;
-
如果是字符串类型的字段,字段的长度较长,可以针对字段的特点,建立前缀索引 ;
-
尽量使用联合索引,减少单列索引,查询时,联合索引很多时候可以覆盖索引,洁身存储空间,避免回表,提高查询效率 ;
-
要控制索引的数量,索引不是多多益善,索引越多,维护索引结构的代价也就越大,会印象增删改的效率 ;
-
如果索引列不能存储NULL值,请在创建表的时候使用NOT NULL约束它。当优化器知道每列是否包含NULL值是,它可以更好地确定哪个索引最有效地用于查询 ;
什么情况下索引会失效
1.违反最左前缀法则
如果索引了多列,要遵守最左前缀法则。
指的是查村从索引的最左列开始,并且不跳过索引中的列。匹配最左前缀法则,走索引 :
违反了最左前缀法则 ,索引失效:
如果符合最左法则,但是出现跳跃某一列,只有最左列索引会生效 :
2.范围查询右边的列,不能使用索引
根据前面的两个字段name,status查询时走索引的,但是最后一个条件address没有用到索引 ;
3.不要在索引列上进行运算操作,索引将失效
4.字符串不加单引号,造成索引失效
在查询时,没有对字符串加单引号,MySql的查询优化器,会自动进行类型转换,造成索引失效 。
5.以%开头的Like模糊查询,索引失效。
-
如果仅仅时尾部模糊匹配,索引不会失效。
-
如果头部模糊匹配,索引失效 。
-
前面两个都失效 ;
总结
面试官:什么情况下索引会失效 ?
候选人:嗯,这个情况比较多,我说一些自己的经验,以前遇到过的
比如,索引在使用的时候没有遵循最左匹配法则,第二个是,模糊查询,如果%号在前面也会导致索引失效。如果在添加索引的字段上进行了运算操作或者类型转换也都会导致索引失效。
我们之前还遇到过一个就是,如果使用了复合索引,中间使用了范围查询,右边的条件索引也会失效
所以,通常情况下,想要判断出这条sql是否有索引失效的情况,可以使用explain执行计划来分析
sql优化经验
1.表的设计优化
表的设计优化(参考阿里开发手册《嵩山版》)
-
比如设置合适的数值(tinyint int bigint),要根据实际情况数值大小选择 ;
-
比如设置合适的字符串类型(char 和 varchar),char定长效率高,varchar可变长度,效率变低 ;
2.sql语句优化
-
select语句必须知名字段名称(避免直接使用select *) ;
-
尽量使用覆盖索引,使用select * 很可能触发回表查询 ;
-
-
SQL语句避免索引失效的写法
-
尽量用union all 代替union, union会多一次过滤,效率低 :
-
-
union会过滤重复数据,保证数据唯一性,能在SQL查询结果一定不会重复的情况下,尽量不用union ;
-
要保证数据的唯一性的话,在java代码中去重效率更高,不要再sql中处理 ;
-
-
避免在where子句中对字段进行表达式操作 ;
例如之前索引失效中substring操作会导致索引失效情况 ;
-
Join优化1,能用innerjoin就不用left joinn right join,如果必须使用,一定要以小表为驱动 ;
-
-
内连接会对两个表进行优化,优先把小表放在外边,把打表放在里边。
-
left join或right join,不会重新调整顺序 ;
-
-
在里面查询结束之后,只用3次连接查询即可,效率更高 ;
3.主从复制,读写分离
4.索引优化
5.分库分表
当表的数据特别大的时候,进行分库分表操作 ;
6.总结
面试官:sql的优化的经验
候选人:嗯,这个在项目还是挺常见的,当然如果直说sql优化的话,我们会从这几方面考虑,比如
建表的时候、使用索引、sql语句的编写、主从复制,读写分离,还有一个是如果量比较大的话,可以考虑分库分表
面试官:创建表的时候,你们是如何优化的呢?
候选人:这个我们主要参考的阿里出的那个开发手册《嵩山版》,就比如,在定义字段的时候需要结合字段的内容来选择合适的类型,如果是数值的话,像tinyint、int 、bigint这些类型,要根据实际情况选择。如果是字符串类型,也是结合存储的内容来选择char和varchar或者text类型
面试官:那在使用索引的时候,是如何优化呢?
候选人:【参考索引创建原则 进行描述】
面试官:你平时对sql语句做了哪些优化呢?
候选人:嗯,这个也有很多,比如SELECT语句务必指明字段名称,不要直接使用select * ,还有就是要注意SQL语句避免造成索引失效的写法;如果是聚合查询,尽量用union all代替union ,union会多一次过滤,效率比较低;如果是表关联的话,尽量使用innerjoin ,不要使用用left join right join,如必须使用 一定要以小表为驱动;
事务相关
事务是一组操作的组合,是一个不可分割的工作单位,事务会把所有操作作为一个整体一起向系统提交或撤销操作请求,即这些操作要么同时成功,要么同时失败 ;
事务的特性
ACID
-
原子性(Atomicity):事务是不可分割的最小操作单元,要么全部成功,要么全部失败。
-
一致性(Consistency):事务完成时,必须使所有的数据都保持一致状态。
-
隔离性(Isolation):数据库系统提供的隔离机制,保证事务在不受外部并发操作影响的独立环境下运行。
-
持久性(Durability):事务一旦提交或回滚,它对数据库中的数据的改变就是永久的。
总结
面试官:事务的特性是什么?可以详细说一下吗?
候选人:嗯,这个比较清楚,ACID,分别指的是:原子性、一致性、隔离性、持久性;我举个例子:
A向B转账500,转账成功,A扣除500元,B增加500元,原子操作体现在要么都成功,要么都失败
在转账的过程中,数据要一致,A扣除了500,B必须增加500
在转账的过程中,隔离性体现在A像B转账,不能受其他事务干扰
在转账的过程中,持久性体现在事务提交后,要把数据持久化(可以说是落盘操作)
并发事务
脏读
事务A没提交但是展示修改了数据库的数据 ;
事务B读取到了事务A修改了但是还没有提交的数据;
如果事务A出现回滚,那么B也就查到了脏数据 ;
不可重复读
事务先后读取同一条数据 ,在这之间数据被另一个事务的update操作修改了;
读的同一条数据,但是前后不同结果 ;
幻读
查询数据时,没有对应的数据行,插入时,又发现这行数据已经存在 ;
然后再次查询,在解决了不可重复读的基础上,还是查不到 ;
幻读和不可重复读区别
-
不可重复读是结果集数量不变,但是内容变化了,由update引发;
-
幻读指的是结果集数量变化了,针对insert和delete操作 ;
解决:对事物进行隔离
-
mysql的默认级别是可重复读 ;
-
Serializable串行化效率低,约等于加锁,一个事务提交完之后,其它事务才能运行,基本失去了并发 ;
-
事务隔离级别越高,数据越安全,但是性能越低 ;
总结
面试官:并发事务带来哪些问题?
候选人:
我们在项目开发中,多个事务并发进行是经常发生的,并发也是必然的,有可能导致一些问题
第一是脏读, 当一个事务正在访问数据并且对数据进行了修改,而这种修改还没有提交到数据库中,这时另外一个事务也访问了这个数据,因为这个数据是还没有提交的数据,那么另外一个事务读到的这个数据是“脏数据”,依据“脏数据”所做的操作可能是不正确的。
第二是不可重复读:比如在一个事务内多次读同一数据。在这个事务还没有结束时,另一个事务也访问该数据。那么,在第一个事务中的两次读数据之间,由于第二个事务的修改导致第一个事务两次读取的数据可能不太一样。这就发生了在一个事务内两次读到的数据是不一样的情况,因此称为不可重复读。
第三是幻读(Phantom read):幻读与不可重复读类似。它发生在一个事务(T1)读取了几行数据,接着另一个并发事务(T2)插入了一些数据时。在随后的查询中,第一个事务(T1)就会发现多了一些原本不存在的记录,就好像发生了幻觉一样,所以称为幻读。
面试官:怎么解决这些问题呢?MySQL的默认隔离级别是?
候选人:解决方案是对事务进行隔离
MySQL支持四种隔离级别,分别有:
第一个是,未提交读(read uncommitted)它解决不了刚才提出的所有问题,一般项目中也不用这个。第二个是读已提交(read committed)它能解决脏读的问题的,但是解决不了不可重复读和幻读。第三个是可重复读(repeatable read)它能解决脏读和不可重复读,但是解决不了幻读,这个也是mysql默认的隔离级别。第四个是串行化(serializable)它可以解决刚才提出来的所有问题,但是由于让是事务串行执行的,性能比较低。所以,我们一般使用的都是mysql默认的隔离级别:可重复读
undo log和redo log的区别
-
缓冲池(buffer pool):主内存中的一个区域,里面可以缓存磁盘上经常操作的真实数据,在执行增删改查操作时,先操作缓冲池中的数据(若缓冲池没有数据,则从磁盘加载并缓存),以一定频率刷新到磁盘,从而减少磁盘IO,加快处理速度
-
数据页(page):是InnoDB 存储引擎磁盘管理的最小单元,每个页的大小默认为 16KB。页中存储的是行数据;
-
当操作来的时候,先操作内存中的数据;
-
还未同步到磁盘的数据,如果宕机,内存中的数据消失,就违背了事务的特性,没有持久化 ;
redo log
重做日志,记录的是事务提交时数据页的物理修改,是用来实现事务的持久性。
该日志文件由两部分组成:重做日志缓冲(redo log buffer)以及重做日志文件(redo log file),前者是在内存中,后者在磁盘中。当事务提交之后会把所有修改信息都存到该日志文件中, 用于在刷新脏页到磁盘,发生错误时, 进行数据恢复使用。
redo log的意义
-
在操作的时候,可能有多条事务操作 ,如果同步刷新,在保存数据到磁盘的时候,都是随机的磁盘IO,性能是非常低的 ,不能采用 ;
-
使用redo log , 因为记录都是追加的,都是顺序的磁盘io,性能高 ;
undo log
回滚日志,用于记录数据被修改前的信息 , 作用包含两个 : 提供回滚 和 MVCC(多版本并发控制) 。undo log和redo log记录物理日志不一样,它是逻辑日志。
-
可以认为当delete一条记录时,undo log中会记录一条对应的insert记录,反之亦然,
-
当update一条记录时,它记录一条对应相反的update记录。
-
当执行rollback时,就可以从undo log中的逻辑记录读取到相应的内容并进行回滚。
undo log保证了事务的原子性和一致性 ;
总结
面试官:undo log和redo log的区别
候选人:好的,其中redo log日志记录的是数据页的物理变化,服务宕机可用来同步数据,而undo log 不同,它主要记录的是逻辑日志,当事务回滚时,通过逆操作恢复原来的数据,比如我们删除一条数据的时候,就会在undo log日志文件中新增一条delete语句,如果发生回滚就执行逆操作;
redo log保证了事务的持久性,undo log保证了事务的原子性和一致性
事务的隔离性如何保证 :
-
锁:排他锁(如一个事务获取了一个数据行的排他锁,其他事务就不能再获取该行的其他锁)
-
mvcc : 多版本并发控制;
解决读写并发,提高性能,写会加排他锁,读加共享锁,
MVCC
全称Multi-Version Concurrency Control,多版本并发控制。指维护一个数据的多个版本,使得读写操作没有冲突 ;
MVCC的具体首先,主要依赖于数据库记录中的
-
隐藏字段
-
undo log日志
-
readView
隐藏字段
undo log
回滚日志,在insert,update,delete的时候产生的便于数据回滚的日志。
-
当insert的时候,产生的undo log日志只在回滚时需要,在事务提交之后,可被立即删除 ;
-
而update,delete的时候,产生的uodo log日志不仅在回滚时需要,mvcc版本访问也需要,不会立即被删除 ;
undo log 版本链
不同事务或相同事务对同一条记录进行修改,会导致该记录的undo log生成一条记录版本链表,链表的头部时最新的旧纪录,链表尾部是最早的旧纪录 ;
readview
-
readview :
ReadView(读视图) 是快照读 SQL执行MVCC提取数据的依据,记录并维护系统当前活跃的事务(未提交) id ;
-
当前读
读取的是记录的最新版本,读取时还要保证其他并发事务不能修改当前记录,会对读取的记录进行加锁。对于我们日常的操作,如:select ... lock in share mode(共享锁),select ... for update、update、insert、delete(排他锁)都是一种当前读。
-
快照读
简单的select(不加锁)就是快照读,快照读,读取的是记录数据的可见版本,有可能是历史数据,不加锁,是非阻塞读。
-
-
Read Committed:每次select,都生成一个快照读 , RC能够读到不一样的数据 ;
-
Repeatable Read:开启事务后第一个select语句才是快照读的地方,解决了可重复读的问题 ,在同一个事务之内,不管查询多少次,都会查到相同的记录 ;
-
RC新开一个readview , RR每次都使用第一个readview ;
-
实现原理
ReadView中包含了4个核心字段 :
字段 | 含义 |
---|---|
m_ids | 当前活跃的事务ID集合 |
min_trx_id | 最小活跃事务ID |
max_trx_id | 预分配事务ID,当前最大事务ID+1(因为事务ID是自增的) |
creator_trx_id | ReadView创建者的事务ID |
-
活跃的事务 指 已经开启但是未提交的事务 ;
对于上图中事务5开启的查询id=30的readview :
-
m_ids : {3,4,5}
-
min_trx_id : 3
-
max_trx_id : 5+1=6 ;
-
creator_trx_id : 5
readView为了能够实现读取快照读中最准确的数据,定义了一些数据访问的规则 :
不同的隔离级别,生成的ReadView的时机不同 :
-
READ COMMITED : 在事务中每一次执行快照读时生成ReadView ;
-
Repeatable Read : 仅在事务中第一次执行快照读的时候生成ReadView,后续复用改ReadView ;
RC
-
事务5的第一次查询语句只能够查到事务2的记录 ;
-
事务5的第一次查询语句只能够查到事务3的记录 ;
-
只能访问提交的版本,只能读取已提交的数据 ,活跃的版本暂时不能访问,也就是读已提交 ;
RR
RR隔离级别下,仅在事务中第一次执行快照读时生成ReadView,后续复用该ReadView ;
面试官:事务中的隔离性是如何保证的呢?(你解释一下MVCC)
候选人:事务的隔离性是由锁和mvcc实现的。
其中mvcc的意思是多版本并发控制。指维护一个数据的多个版本,使得读写操作没有冲突,它的底层实现主要是分为了三个部分,第一个是隐藏字段,第二个是undo log日志,第三个是readView读视图
隐藏字段是指:在mysql中给每个表都设置了隐藏字段,有一个是trx_id(事务id),记录每一次操作的事务id,是自增的;另一个字段是roll_pointer(回滚指针),指向上一个版本的事务版本记录地址
undo log主要的作用是记录回滚日志,存储老版本数据,在内部会形成一个版本链,在多个事务并行操作某一行记录,记录不同事务修改数据的版本,通过roll_pointer指针形成一个链表
readView解决的是一个事务查询选择版本的问题,在内部定义了一些匹配规则和当前的一些事务id判断该访问那个版本的数据,不同的隔离级别快照读是不一样的,最终的访问的结果不一样。如果是rc隔离级别,每一次执行快照读时生成ReadView,如果是rr隔离级别仅在事务中第一次执行快照读时生成ReadView,后续复用;
MySql主从同步原理
-
MySQL主从复制的核心就是二进制日志 ;
-
二进制日志(BINLOG)记录了所有的DDL和DML语句,但不包括数据查询语句 ;
复制分成三步:
1.Master 主库在事务提交时,会把数据变更记录在二进制日志文件 Binlog 中。
2.从库读取主库的二进制日志文件 Binlog ,写入到从库的中继日志 Relay Log 。
3.slave重做中继日志中的事件,将改变反映它自己的数据。
分库分表
解决存储压力 :
分库分表的时机:
1,前提,项目业务数据逐渐增多,或业务发展比较迅速 ,单表的数据量达到1000W或20G以后 ;
2,优化已解决不了性能问题(主从读写分离、查询索引…)
3,IO瓶颈(磁盘IO、网络IO)、CPU瓶颈(聚合查询、连接数太多)
拆分策略 :
垂直拆分
分库 :
-
垂直分库 : 以表为依据,根据业务将不同表才分到不同库中 ;
特点 :
-
按业务对数据分级管理,维护,监控,扩展 ;
-
在高并发下,提高磁盘IO和数量连接数 ;
分表
垂直按列分 ;
-
以字段为依据,根据字段属性将不同字段才分到不同表中 ;
拆分规则 :
-
把不常用的字段单独放在一张表 ;
-
把text,blob等大字段拆分出来放在附表中 ;
-
类似订单表和订单细节表 ;
特点 :
-
冷热数据分离
-
减少IO过度争抢,两表互不影响 ;
水平拆分
分库
分表
水平按行分 :
问题
分库之后的问题:
-
分布式事务一致性问题
-
跨节点关联查询
-
跨节点分页、排序函数
-
主键避重
分库分表中间件:
-
sharding-sphere
-
mycat
总结
业务介绍
1,根据自己简历上的项目,想一个数据量较大业务(请求数多或业务累积大)
2,达到了什么样的量级(单表1000万或超过20G)
具体拆分策略
1,水平分库,将一个库的数据拆分到多个库中,解决海量数据存储和高并发的问题
2,水平分表,解决单表存储和性能的问题
3,垂直分库,根据业务进行拆分,高并发下提高磁盘IO和网络连接数
4,垂直分表,冷热数据分离,多表互不影响
水平分库和水平分表都需要使用中间件解决访问的问题 ;
面试官:你们项目用过MySQL的分库分表吗?
候选人:
嗯,因为我们都是微服务开发,每个微服务对应了一个数据库,是根据业务进行拆分的,这个其实就是垂直拆分。
面试官:那你之前使用过水平分库吗?
候选人:
嗯,这个是使用过的,我们当时的业务是(xxx),一开始,我们也是单库,后来这个业务逐渐发展,业务量上来的很迅速,其中(xx)表已经存放了超过1000万的数据,我们做了很多优化也不好使,性能依然很慢,所以当时就使用了水平分库。
我们一开始先做了3台服务器对应了3个数据库,由于库多了,需要分片,我们当时采用的mycat来作为数据库的中间件。数据都是按照id(自增)取模的方式来存取的。
当然一开始的时候,那些旧数据,我们做了一些清洗的工作,我们也是按照id取模规则分别存储到了各个数据库中,好处就是可以让各个数据库分摊存储和读取的压力,解决了我们当时性能的问题
‘
联合索引
在MySQL中,联合索引(也称为复合索引或多列索引)是基于表中的多个列创建的索引。这种索引可以提高多列查询的性能,特别是当查询条件涉及这些列时。
对于联合索引,叶子节点并不包含行记录的全部数据。叶子节点除了包含键值以外,每个叶子节点中的索引行中还包含了一个书签(bookmark)。该书签用来告诉InnoDB存储引擎哪里可以找到与索引相对应的行数据。由于InnoDB存储引擎表时索引组织表,因此InnoDB存储引擎的辅助索引的书签就是相应行数据的聚集索引键。
最左前缀匹配法则
最左前缀匹配原则指的是在使用联合索引时,MySQL 会根据索引中的字段顺序,从左到右依次匹配查询条件中的字段。如果查询条件与索引中的最左侧字段相匹配,那么 MySQL 就会使用索引来过滤数据,这样可以提高查询效率。