# Mysql面试
# 优化
# 定位慢查询
如何定位慢查询
方案一:开源工具
- 调试工具:Arthas
- 运维工具:Prometheus、Skywalking
方案二:MYSQL自带的慢日志
慢查询日志记录了所有执行时间超过指定参数(默认10秒)的所有SQL语句的日志
如果要开启慢查询日志,需要在MYSQL的配置文件(/etc/my.cnf)中配置如下信息:
# 开启Mysql慢查询日志开关
slow_query_log = 1
# 设置慢查询的时间为2秒,SQL语句执行时间超过2秒,就视为慢查询,记录入日志
long_query_time = 2
配置完成后重新启动MYSQL服务器进行测试,查看慢查询日志中记录的信息/var/lib/mysql/localhost-slow.log
TIP
如何定位慢查询?
- 介绍当时产生问题的场景(当时的一个接口测试的时候非常慢,压测结果大概5秒钟)
- 我们系统中采用了运维工具(Skywalking),可以监测出哪个接口,最终因为是sql的问题
- 在mysql中开启了慢查询日志,设置的值为2秒,一旦sql执行超过2秒就会记录到日志中(调试阶段)
# SQL执行计划
- possible_key 当前sql可能会使用到的索引
- key 当前sql实际命中的索引
- key_len 索引占用的大小
- 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:全盘扫描
TIP
如果某个SQL语句执行很慢,如何去分析?
可以采用MySQL自带的分析工具 EXPLAIN
- 通过key和key_len检查是否命中了索引(若索引本身已经存在,判断是否有失效的情况)
- 通过type字段查看sql是否有进一步的优化空间,是否存在全索引扫描或全盘扫描
- 通过extra建议判断,是否出现了回表的情况,如果出现了,可以尝试添加索引或修改返回字段来修复
# 索引
传统的查询方法,是按照表的顺序遍历的,不论查询几条数据,MySQL 需要将表的数据从头到尾遍历一遍。
在我们添加完索引之后,MySQL 一般通过 BTREE 算法生成一个索引文件,在查询数据库时,找到索引文件进行遍历,在比较小的索引数据里查找,然后映射到对应的数据,能大幅提升查找的效率。
索引(index)是帮助Mysql高效获取数据的数据结构(有序)。在数据之外,数据库还维护着特定查找算法的数据结构(B+树),这些数据结构以某种方式引用(指向)数据,这样就可以在这些数据结构上实现高级查找算法,这种数据结构就是索引。
# 存储引擎
MySQL 5.5 之前,MyISAM 引擎是 MySQL 的默认存储引擎,MySQL 5.5 版本之后,InnoDB 代替MyISAM成为 MySQL 的默认存储引擎。
MyISAM | InnoDB | |
---|---|---|
是否支持行级锁 | 只有表级锁(table-level locking) | 支持行级锁(row-level locking)和表级锁,默认为行级锁 |
是否支持事务 | 不提供事务支持 | 提供事务支持,具有提交(commit)和回滚(rollback)事务的能力。并且默认使用的 REPEATABLE-READ隔离级别可以解决幻读问题发生(基于 MVCC 和 Next-Key Lock)。 |
是否支持外键 | 不支持外键 | 支持外键 |
是否支持数据库异常崩溃后的安全恢复 | 不支持 | 支持。恢复的过程依赖于 redo log |
是否支持 MVCC | 不支持 | 支持,MVCC是行级锁的一个升级,可以有效减少加锁操作,提高性能 |
索引实现 | MyISAM 引擎中,B+Tree 叶节点的 data 域存放的是数据记录的地址。在索引检索的时候,首先按照 B+Tree 搜索算法搜索索引,如果指定的 Key 存在,则取出其 data 域的值,然后以 data 域的值为地址读取相应的数据记录。这被称为“非聚簇索引(非聚集索引)” | InnoDB 引擎中,其数据文件本身就是索引文件。树的叶节点 data 域保存了完整的数据记录。这个索引的 key 是数据表的主键,因此 InnoDB 表数据文件本身就是主索引。这被称为“聚簇索引(聚集索引)”其余的索引都作为 辅助索引 ,辅助索引的 data 域存储相应记录主键的值而不是地址。在根据主索引搜索时,直接找到 key 所在的节点即可取出数据;在根据辅助索引查找时,则需要先取出主键的值,再走一遍主索引。 |
性能差别 | MyISAM 因为读写不能并发,它的处理能力跟核数没关系 | InnoDB 的性能比 MyISAM 更强大,不管是在读写混合模式下还是只读模式下,随着 CPU 核数的增加,InnoDB 的读写能力呈线性增长。 |
# 索引底层数据结构
底层数据结构选型
- Hash表
- 数组+链表的结构,通过hash函数计算出key在数组中的位置,然后如果出现hash冲突就通过链表来解决。
- Hash 索引不支持顺序和范围查询,并且每次 IO 只能取一个,范围查询时 Hash 索引效率极低。
- 无法利用索引排序。
- 在有大量重复键值情况下,哈希索引的效率也是极低的,因为存在所谓的哈希碰撞问题。
- 数组+链表的结构,通过hash函数计算出key在数组中的位置,然后如果出现hash冲突就通过链表来解决。
- 二叉查找树(BST)
- 当二叉查找树是平衡的时候,也就是树的每个节点的左右子树深度相差不超过 1 的时候,查询的时间复杂度为 O(log2(N)),具有比较高的效率。
- 当二叉查找树不平衡时,例如在最坏情况下(有序插入节点),树会退化成线性链表(也被称为斜树),导致查询效率急剧下降,时间复杂退化为 O(N)。
- AVL树
- 计算机科学中最早被发明的自平衡二叉查找树,任何节点的左右子树高度之差不超过 1,AVL 树采用旋转操作来保持平衡
- 由于 AVL 树需要频繁地进行旋转操作来保持平衡,因此会有较大的计算开销进而降低了查询性能。并且, 在使用 AVL 树时,每个树节点仅存储一个数据,而每次进行磁盘 IO 时只能读取一个节点的数据,如果需要查询的数据分布在多个节点上,那么就需要进行多次磁盘 IO。 磁盘 IO 是一项耗时的操作,在设计数据库索引时,我们需要优先考虑如何最大限度地减少磁盘 IO 操作的次数。
- 计算机科学中最早被发明的自平衡二叉查找树,任何节点的左右子树高度之差不超过 1,AVL 树采用旋转操作来保持平衡
- 红黑树
- 红黑树是一种自平衡二叉查找树,通过在插入和删除节点时进行颜色变换和旋转操作,使得树始终保持平衡状态,和 AVL 树不同的是,红黑树并不追求严格的平衡,而是大致的平衡。
- 因为红黑树的平衡性相对较弱,可能会导致树的高度较高,这可能会导致一些数据需要进行多次磁盘 IO 操作才能查询到。
- B树&B+树
- B 树也称 B-树,全称为 多路平衡查找树 ,B+ 树是 B 树的一种变体。B 树和 B+树中的 B 是
Balanced
(平衡)的意思。 - 此时每个节点可以存放的关键字相比红黑树和AVL树更多了,更“矮胖”,磁盘IO更少。
- B 树也称 B-树,全称为 多路平衡查找树 ,B+ 树是 B 树的一种变体。B 树和 B+树中的 B 是
B-Tree
B+Tree聚簇索引
- 数据都保存在叶子节点中,且是有序的
- 非叶子节点的子树 等于关键字数量
- 叶子节点是 双向链表 形式保存兄弟节点的指针
- Mysql的B+树中各个页之间是通过双向链表连接的,叶子节点中的数据是通过单向链表连接的
B+Tree非聚簇索引
- 叶子节点中保存的是主键的值
B树与B+树对比
- 查找时磁盘 I/O 次数更少,因为 B+树的非叶子结点可以存储更多的关键字,数据量相同的情况下,B+树更加 “矮胖” ,查询效率更高,且在范围查询时所需的磁盘IO更少,磁盘读写代价更低;
- B+树查询所有关键字的磁盘 I/O 次数都一样,查询效率更加稳定
- B+树便于扫库和区间查询
TIP
了解过索引吗?(什么是索引)
- 索引(index)是帮助Mysql高效获取数据的数据结构(有序)
- 提高数据检索的效率,降低数据库的IO成本(不需要全表扫描)
- 通过索引对数据进行排序,降低数据排序的成本,降低了CPU的消耗
Mysql索引的底层数据结构是什么
Mysql存储引擎无论是innoDB还是MyISAM都是采用B+树的数据结构来做存储索引
- 阶数更多,路径更短
- 磁盘读写代价B+树更低,非叶子节点只存储指针,叶子节点存储数据
- B+树便于扫库和区间查询,叶子节点是一个双向链表
# 聚簇索引和非聚簇索引
聚簇(聚集)索引和非聚簇(二级)索引
分类 | 含义 | 特点 |
---|---|---|
聚集索引(Clustered Index) | 将数据存储与索引放到了一块,索引结构的叶子节点保存了行数据 | 必须有且只有一个 |
二级索引(Secondary Index) | 将数据与索引分开存储,索引节点的叶子节点关联的是对应的主键 | 可以存在多个 |
聚集索引选取规则:
- 如果存在主键,主键索引就是聚集索引。
- 如果不存在主键,将使用第一个唯一(UNIQUE)索引作为聚集索引。
- 如果表没有主键,或没有合适的唯一索引,则InnoDB会自动生成一个rowid作为隐藏的聚集索引。
TIP
什么是聚簇索引什么是非聚簇索引?
聚簇索引(聚集索引):数据与索引放到一块,B+树的叶子节点保存了整行数据,有且只有一个
非聚簇索引(二级索引):数据与索引分开存储,B+树的叶子节点保存对应的主键,可以有多个
知道什么是回表查询吗?
先通过二级索引去找到对应主键值,再根据主键值去聚集索引中找到整行的数据,这个过程就叫回表查询。
覆盖索引
覆盖索引是指查询使用了索引,并且需要返回的列在该索引中已经全部能够找到。
考虑下面的数据表
id | name | gender | createdate |
---|---|---|---|
2 | Arm | 1 | 2021-01-01 |
3 | Lily | 0 | 2021-05-01 |
5 | Rose | 0 | 2021-02-14 |
6 | Zoo | 1 | 2021-06-01 |
8 | Doc | 1 | 2021-03-08 |
11 | Lee | 1 | 2020-12-03 |
Sql语句
select * from tb_user where id = 1; # 覆盖索引
select id,name from tb_user where name = ‘Arm’; # 覆盖索引
select id,name,gender from tb_user where name = ‘Arm’; # 非覆盖索引(需要回表查询)
TIP
知道什么叫覆盖索引吗?
覆盖索引是指查询使用了索引,并且需要返回的列在该索引中已经全部能够找到。
- 使用id查询,直接走聚集索引查询,一次索引扫描,直接返回数据,性能高。
- 如果返回的列中没有创建索引,有可能会触发回表查询,尽量避免使用select *
Mysql超大分页处理:在数据量比较大时,limit分页查询,需要对数据进行排序,效率低,怎么解决?
select * from tb_sku limit 9000000,10 在进行分页查询时,执行 limit 9000000,10 需要MySQL排序前9000010 记录,最后仅仅返回 9000000 - 9000010 的记录,其他记录丢弃,查询排序的代价非常大
select * from tb_sku t, (select id from tb_sku order by id limit 9000000,10) a where t.id = a.id;
分页查询时通过创建覆盖索引和添加子查询的形式进行优化能够很好的提升性能。
- 先分页查询数据的id字段,确定了id之后,再用子查询来过滤,此时只查询这个id列表中的数据就可以了
- 因为查询id的时候,走的覆盖索引,效率可以提升很多
# 索引创建原则
- 针对于数据量较大,且查询比较频繁的表建立索引。[单表超过10万数据(增加用户体验)]
- 针对于常作为查询条件(where)、排序(order by)、分组(group by)操作的字段建立索引。
- 尽量选择区分度高的列作为索引,尽量建立唯一索引,区分度越高,使用索引的效率越高。
- 如果是字符串类型的字段,字段的长度较长,可以针对于字段的特点,建立前缀索引。
- 尽量使用联合索引,减少单列索引,查询时,联合索引很多时候可以覆盖索引,节省存储空间,避免回表,提高查询效率。
- 要控制索引的数量,索引并不是多多益善,索引越多,维护索引结构的代价也就越大,会影响增删改的效率。
- 如果索引列不能存储NULL值,请在创建表时使用NOT NULL约束它。当优化器知道每列是否包含NULL值时,它可以更好地确定哪个索引最有效地用于查询。
TIP
索引的创建原则有哪些?
嗯,这个情况有很多,不过都有一个大前提,就是表中的数据要超过10万以上,我们才会创建索引,并且添加索引的字段是查询比较频繁的字段,一般也是像作为查询条件,排序字段或分组的字段这些。
还有就是,我们通常创建索引的时候都是使用复合索引来创建,一条sql的返回值,尽量使用覆盖索引,如果字段的区分度不高的话,我们也会把它放在组合索引后面的字段。
如果某一个字段的内容较长,我们会考虑使用前缀索引来使用,当然并不是所有的字段都要添加索引,这个索引的数量也要控制,因为添加索引也会导致新增改的速度变慢
# 索引失效场景
- 违反最左前缀法则,索引失效
- 范围查询右边的列,索引失效
- 不要在索引列上进行运算操作,索引将失效
- 字符串不加单引号,会造成索引失效(类型转换)
- 以 %开头 的Like模糊查询,索引失效
TIP
嗯,这个情况比较多,我说一些自己的经验,以前遇到过的:
比如,索引在使用的时候没有遵循最左匹配法则,第二个是,模糊查询,如果%号在前面也会导致索引失效。如果在添加索引的字段上进行了运算操作或者类型转换也都会导致索引失效。
我们之前还遇到过一个就是,如果使用了复合索引,中间使用了范围查询,右边的条件索引也会失效
所以,通常情况下,想要判断出这条sql是否有索引失效的情况,可以使用explain执行计划来分析
# SQL优化经验
- 表的设计优化(参考阿里开发手册《嵩山版》)
- 比如设置合适的数值(tinyint int bigint),要根据实际情况选择
- 比如设置合适的字符串类型(char和varchar)char定长效率高,varchar可变长度,效率稍低
- 索引优化
- 参考优化创建原则和索引失效
- SQL语句优化
- SELECT语句务必指明字段名称(避免直接使用select * )
- SQL语句要避免造成索引失效的写法
- 尽量用union all代替union union会多一次过滤,效率低
- 避免在where子句中对字段进行表达式操作
- Join优化能用innerjoin 就不用left join right join,如必须使用 一定要以小表为驱动,内连接会对两个表进行优化,优先把小表放到外边,把大表放到里边。left join 或 right join不会重新调整顺序
- 主从复制、读写分离
- 如果数据库的使用场景读的操作比较多的时候,为了避免写的操作所造成的性能影响,可以采用读写分离的架构。读写分离解决的是,数据库的写入,影响了查询的效率。
- 分库分表
# 其他面试题
# 事务相关
何为事务? 一言蔽之,事务是逻辑上的一组操作,要么都执行,要么都不执行。大多数情况下,我们在谈论事务的时候,如果没有特指分布式事务,往往指的就是数据库事务。数据库事务在我们日常开发中接触的最多了。如果你的项目属于单体架构的话,你接触到的往往就是数据库事务了。数据库事务可以保证多个对数据库的操作(也就是 SQL 语句)构成一个逻辑上的整体。构成这个逻辑上的整体的这些数据库操作遵循:要么全部执行成功,要么全部不执行 。
关系型数据库(例如:MySQL、SQL Server、Oracle 等)事务都有 ACID 特性
# 事务特性
ACID 特性
- 原子性(Atomicity):事务是最小的执行单位,不允许分割。事务的原子性确保动作要么全部完成,要么完全不起作用
- 一致性(Consistency):执行事务前后,数据保持一致,例如转账业务中,无论事务是否成功,转账者和收款人的总额应该是不变的
- 隔离性(Isolation):并发访问数据库时,一个用户的事务不被其他事务所干扰,各并发事务之间数据库是独立的
- 持久性(Durability):一个事务被提交之后。它对数据库中数据的改变是持久的,即使数据库发生故障也不应该对其有任何影响
只有保证了事务的持久性、原子性、隔离性之后,一致性才能得到保障。也就是说A、I、D是手段,C是目的!
# 隔离级别
并发事务带来了哪些问题?
在典型的应用程序中,多个事务并发运行,经常会操作相同的数据来完成各自的任务(多个用户对同一数据进行操作)。并发虽然是必须的,但可能会导致以下的问题。
脏读(Dirty read)
一个事务读取数据并且对数据进行了修改,这个修改对其他事务来说是可见的,即使当前事务没有提交。这时另外一个事务读取了这个还未提交的数据,但第一个事务突然回滚,导致数据并没有被提交到数据库,那第二个事务读取到的就是脏数据,这也就是脏读的由来。
例如:事务 1 读取某表中的数据 A=20,事务 1 修改 A=A-1,事务 2 读取到 A = 19,事务 1 回滚导致对 A 的修改并为提交到数据库, A 的值还是 20。
丢失修改(Lost to modify)
在一个事务读取一个数据时,另外一个事务也访问了该数据,那么在第一个事务中修改了这个数据后,第二个事务也修改了这个数据。这样第一个事务内的修改结果就被丢失,因此称为丢失修改。
例如:事务 1 读取某表中的数据 A=20,事务 2 也读取 A=20,事务 1 先修改 A=A-1,事务 2 后来也修改 A=A-1,最终结果 A=19,事务 1 的修改被丢失。
不可重复读(Unrepeatable read)
指在一个事务内多次读同一数据。在这个事务还没有结束时,另一个事务也访问该数据。那么,在第一个事务中的两次读数据之间,由于第二个事务的修改导致第一个事务两次读取的数据可能不太一样。这就发生了在一个事务内两次读到的数据是不一样的情况,因此称为不可重复读。
例如:事务 1 读取某表中的数据 A=20,事务 2 也读取 A=20,事务 1 修改 A=A-1,事务 2 再次读取 A =19,此时读取的结果和第一次读取的结果不同。
幻读(Phantom read)
幻读与不可重复读类似。它发生在一个事务读取了几行数据,接着另一个并发事务插入了一些数据时。在随后的查询中,第一个事务就会发现多了一些原本不存在的记录,就好像发生了幻觉一样,所以称为幻读。
例如:事务 2 读取某个范围的数据,事务 1 在这个范围插入了新的数据,事务 2 再次读取这个范围的数据发现相比于第一次读取的结果多了新的数据。
SQL 标准定义了哪些事务隔离级别?
SQL 标准定义了四个隔离级别:
- READ-UNCOMMITTED(读取未提交):最低的隔离级别,允许读取尚未提交的数据变更,可能会导致脏读、幻读或不可重复读。
- READ-COMMITTED(读取已提交):允许读取并发事务已经提交的数据,可以阻止脏读,但是幻读或不可重复读仍有可能发生。
- REPEATABLE-READ(可重复读):对同一字段的多次读取结果都是一致的,除非数据是被本身事务自己所修改,可以阻止脏读和不可重复读,但幻读仍有可能发生。
- SERIALIZABLE(可串行化):最高的隔离级别,完全服从 ACID 的隔离级别。所有的事务依次逐个执行,这样事务之间就完全不可能产生干扰,也就是说,该级别可以防止脏读、不可重复读以及幻读。
隔离级别 | 脏读 | 不可重复读 | 幻读 |
---|---|---|---|
READ-UNCOMMITTED | √ | √ | √ |
READ-COMMITTED | × | √ | √ |
REPEATABLE-READ | × | × | √ |
SERIALIZABLE | × | × | × |
Mysql日志
参考文章: Mysql三大日志 (opens new window)
- redo log:记录数据页的物理变化,服务宕机时可用来同步数据(保证事物的持久性)
- 每条 redo 记录由“表空间号+数据页号+偏移量+修改数据长度+具体修改的数据”组成
- undo log:记录的是逻辑日志,当事务回归时,通过逆操作恢复原来的数据(保证事务的原子性和一致性)
- binlog:也是逻辑日志,记录内容是语句的原始逻辑,不管用什么存储引擎,只要发生了表数据更新,都会产生 binlog日志。用于数据备份中主备、主主、主从同步数据,保证集群架构中的数据一致性。
通过两阶段提交保证宕机时主从节点的数据一致,否则redo log和binlog可能有一方有数据丢失导致数据恢复后主从节点有一方数据有缺失问题。
事务的隔离性是由锁和mvcc实现的。体现如下:
标准的 SQL 隔离级别定义里,REPEATABLE-READ(可重复读)是不可以防止幻读的。但是!InnoDB 实现的 REPEATABLE-READ 隔离级别其实是可以解决幻读问题发生的。主要有下面两种情况:
- 快照读:由 MVCC 机制来保证不出现幻读。
- 当前读:使用 Next-Key Lock 进行加锁来保证不出现幻读,Next-Key Lock 是行锁(Record Lock)和间隙锁(Gap Lock)的结合,行锁只能锁住已经存在的行,为了避免插入新行,需要依赖间隙锁。
解决幻读的方式有很多,但是它们的核心思想就是一个事务在操作某张表数据的时候,另外一个事务不允许新增或者删除这张表中的数据了。
InnoDB 存储引擎在分布式事务的情况下一般会用到 SERIALIZABLE 隔离级别。
# MVCC
MVCC 是多版本并发控制方法,即对一份数据会存储多个版本,通过事务的可见性来保证事务能看到自己应该看到的版本。通常会有一个全局的版本分配器来为每一行数据设置版本号,版本号是唯一的。
MVCC 在 MySQL 中实现所依赖的手段主要是: 隐藏字段、read view、undo log。
- undo log : undo log 用于记录某行数据的多个版本的数据。
- 回滚日志,存储老版本数据
- 版本链:多个事务并行操作某一行记录,记录不同事务修改数据的版本,通过roll_pointer指针形成一个链表
- read view 和 隐藏字段 : 用来判断当前版本数据的可见性。
- 隐藏字段:
- trix_id(事务id),记录每一次操作的事务id,是自增的
- roll_pointer(回滚指针),指向上一个版本的事务版本记录地址
- read view解决的是一个事务查询选择版本的问题
- 根据read view的匹配规则和当前的一些事务id判断该访问哪个版本的数据
- 不同隔离级别的快照读不同,最终的访问结果不一样
- RC:每一次执行快照读(查询)时生成ReadView
- RR:仅在事务中第一次执行快照读(查询)时生成ReadView,后续复用
- 隐藏字段:
字段 | 含义 |
---|---|
m_ids | 当前活跃的事务ID集合 |
min_trx_id | 最小活跃事务ID |
max_trx_id | 预分配事务ID,当前最大事务ID+1(因为事务ID是自增的) |
creator_trx_id | ReadView创建者的事务ID |
# 主从同步原理
Mysql主从复制的核心就是二进制日志binlog,其中记录的是DDL(数据定义语言)语句和DML(数据操纵语言)语句。
- 主库在事务提交时,会把数据变更记录在二进制日志文件binlog中。
- 从库读取主库的二进制文件binlog,写入到从库的中继日志relay log中。
- 从库重做中继日志中的事件,覆盖自己原来的数据,以保持和主库数据一致。
TIP
Mysql主从同步原理了解吗?
MySQL主从复制的核心就是二进制日志(DDL(数据定义语言)语句和 DML(数据操纵语言)语句),它的步骤是这样的:
第一:主库在事务提交时,会把数据变更记录在二进制日志文件 Binlog 中。
第二:从库读取主库的二进制日志文件 Binlog ,写入到从库的中继日志Relay Log 。
第三:从库重做中继日志中的事件,将改变反映它自己的数据。
# 分库分表
主从分离架构解决的是访问压力大的问题,没法解决海量数据存储的问题。
而分库分表就是为了解决存储压力的问题。
# 分库分表的时机:
- 前提,项目业务数据逐渐增多,或业务发展比较迅速 单表数据量达到1000W或20G以后
- 优化已解决不了性能问题(主从读写分离、查询索引...)
- IO瓶颈(磁盘IO、网络IO)、CPU瓶颈(聚合查询、连接数太多)
# 拆分策略
- 垂直拆分
- 垂直分库
- 以表为依据,根据业务将不同表拆分到不同库中
- 特点
- 按业务对数据分级管理、维护、监控、扩展
- 在高并发下,提高磁盘IO和数据量连接数
- 垂直分表
- 以字段为依据,根据字段属性将不同字段拆分到不同表中。
- 特点
- 冷热数据分离
- 减少IO过渡争抢,两表互不影响
- 垂直分库
- 水平拆分
- 水平分库
- 将一个库的数据拆分到多个库中。
- 特点
- 解决了单库大数量,高并发的性能瓶颈问题
- 提高了系统的稳定性和可用性
- 路由规则
- 根据id节点取模
- 按id也就是范围路由,节点1(1-100万 ),节点2(100万-200万)
- 水平分表
- 将一个表的数据拆分到多个表中(可以在同一个库内)。
- 特点
- 优化单一表数据量过大而产生的性能问题
- 避免IO争抢并减少锁表的几率
- 水平分库
# 新的问题和新的技术
- 分库之后的问题
- 分布式事务一致性问题
- 跨节点关联查询
- 跨节点分页、排序函数
- 主键避重
- 分库分表中间件
- sharding-sphere
- mycat
TIP
你们项目用过分库分表吗?
- 业务介绍
- 根据自己简历上的项目,想一个数据量较大业务(请求数多或业务累积大)
- 达到了什么样的量级(单表1000万或超过20G)
- 具体拆分策略
- 水平分库,将一个库的数据拆分到多个库中,解决海量数据存储和高并发的问题
- 水平分表,解决单表存储和性能的问题
- 垂直分库,根据业务进行拆分,高并发下提高磁盘IO和网络连接数
- 垂直分表,冷热数据分离,多表互不影响