MySQL
- 1.索引
- 2.事务
- 3.事物的四⼤特性(ACID)
- 4.并发事务带来的问题
- 5.事务隔离级别,MySQL的默认隔离级别
- 6.锁机制与InnoDB锁算法
- 7.⼤表优化
- 8.池化设计思想及数据库连接池
- 9.分库分表之后,id主键如何处理
1.索引
MySQL索引使⽤的数据结构主要有BTree索引和哈希索引。
对于哈希索引来说,底层的数据结构就是哈希表,因此在绝⼤多数需求为单条记录查询的时候,可以选择哈希索引,查询性能最快;其余⼤部分场景,建议选择BTree索引。
2.事务
3.事物的四⼤特性(ACID)
4.并发事务带来的问题
不可重复读和幻读区别:不可重复读的重点是修改⽐如多次读取⼀条记录发现其中某些列的值被修改,幻读的重点在于新增或者删除⽐如多次读取⼀条记录发现记录增多或减少了。
5.事务隔离级别,MySQL的默认隔离级别
注意:与SQL标准不同的地⽅在于InnoDB存储引擎在REPEATABLEREAD(可重读)事务隔离级别下使⽤的是Next-KeyLock锁算法,因此可以避免幻读的产⽣,这与其他数据库系统(如SQLServer)是不同的。所以说InnoDB存储引擎的默认⽀持的隔离级别是REPEATABLE-READ(可重读)已经可以完全保证事务的隔离性要求,即达到了SQL标准的SERIALIZABLE(可串⾏化)隔离级别。因为隔离级别越低,事务请求的锁越少,所以⼤部分数据库系统的隔离级别都是READ-COMMITTED(读取提交内容),但是你要知道的是InnoDB存储引擎默认使⽤REPEAaTABLE-READ(可重读)并不会有任何性能损失。
InnoDB存储引擎在分布式事务的情况下⼀般会⽤到SERIALIZABLE(可串⾏化)隔离级别。
6.锁机制与InnoDB锁算法
MyISAM和InnoDB存储引擎使⽤的锁:
- MyISAM采⽤表级锁(table-levellocking)。
- InnoDB⽀持⾏级锁(row-levellocking)和表级锁,默认为⾏级锁
相关知识点:
- innodb对于⾏的查询使⽤next-key lock
- Next-locking keying为了解决幻读问题
- 当查询的索引含有唯⼀属性时,将next-key lock降级为record key
- Gap锁设计的⽬的是为了阻⽌多个事务将记录插⼊到同⼀范围内,⽽这会导致幻读问题的产⽣
- 有两种⽅式显式关闭gap锁:(除了外键约束和唯⼀性检查外,其余情况仅使⽤record lock) ①将事务隔离级别设置为RC ②将参数innodb_locks_unsafe_for_binlog设置为1
7.⼤表优化
限定数据的范围
务必禁⽌不带任何限制数据范围条件的查询语句。⽐如:我们当⽤户在查询订单历史的时候,我们可以控制在⼀个⽉的范围内;
读/写分离
经典的数据库拆分⽅案,主库负责写,从库负责读;
垂直分区
根据数据库⾥⾯数据表的相关性进⾏拆分。例如,⽤户表中既有⽤户的登录信息⼜有⽤户的基本信息,可以将⽤户表拆分成两个单独的表,甚⾄放到单独的库做分库。
简单来说垂直拆分是指数据表列的拆分,把⼀张列⽐较多的表拆分为多张表。如下图所示,这样来说⼤家应该就更容易理解了。
垂直拆分的优点:可以使得列数据变⼩,在查询时减少读取的Block数,减少I/O次数。此外,垂直分区可以简化表的结构,易于维护。
垂直拆分的缺点:主键会出现冗余,需要管理冗余列,并会引起Join操作,可以通过在应⽤层进⾏Join来解决。此外,垂直分区会让事务变得更加复杂。
⽔平分区
保持数据表结构不变,通过某种策略存储数据分⽚。这样每⼀⽚数据分散到不同的表或者库中,达到了分布式的⽬的。⽔平拆分可以⽀撑⾮常⼤的数据量。⽔平拆分是指数据表⾏的拆分,表的⾏数超过200万⾏时,就会变慢,这时可以把⼀张的表的数据拆成多张表来存放。举个例⼦:我们可以将⽤户信息表拆分成多个⽤户信息表,这样就可以避免单⼀表数据量过⼤对性能造成影响。
⽔平拆分可以⽀持⾮常⼤的数据量。需要注意的⼀点是:分表仅仅是解决了单⼀表数据过⼤的问题,但由于表的数据还是在同⼀台机器上,其实对于提升MySQL并发能⼒没有什么意义,所以⽔平拆分最好分库。
⽔平拆分能够⽀持⾮常⼤的数据量存储,应⽤端改造也少,但分⽚事务难以解决,跨节点Join性能较差,逻辑复杂。《Java⼯程师修炼之道》的作者推荐尽量不要对数据进⾏分⽚,因为拆分会带来逻辑、部署、运维的各种复杂度,⼀般的数据表在优化得当的情况下⽀撑千万以下的数据量是没有太⼤问题的。如果实在要分⽚,尽量选择客户端分⽚架构,这样可以减少⼀次和中间件的⽹络I/O。
数据库分⽚的两种常⻅⽅案:
- 客户端代理:分⽚逻辑在应⽤端,封装在jar包中,通过修改或者封装JDBC层来实现。当当⽹的Sharding-JDBC、阿⾥的TDDL是两种⽐较常⽤的实现。
- 中间件代理:在应⽤和数据中间加了⼀个代理层。分⽚逻辑统⼀维护在中间件服务中。Mycat、360的Atlas、⽹易的DDB等等都是这种架构的实现。
详细请点击:MySQL大表优化方案
8.池化设计思想及数据库连接池
9.分库分表之后,id主键如何处理
要是分成多个表之后,每个表都是从1开始累加,这样是不对的,我们需要⼀个全局唯⼀的id来⽀持。
⽣成全局id有下⾯这⼏种⽅式:
- UUID:不适合作为主键,因为太⻓了,并且⽆序不可读,查询效率低。⽐较适合⽤于⽣成唯⼀的名字的标示⽐如⽂件的名字。
- 数据库⾃增id:两台数据库分别设置不同步⻓,⽣成不重复ID的策略来实现⾼可⽤。这种⽅式⽣成的id有序,但是需要独⽴部署数据库实例,成本⾼,还会有性能瓶颈。
- 利⽤redis⽣成id:性能⽐较好,灵活⽅便,不依赖于数据库。但是,引⼊了新的组件造成系统更加复杂,可⽤性降低,编码更加复杂,增加了系统成本。
- Twitter的snowflake算法:https://github.com/twitter-archive/snowflake。
- 美团的Leaf分布式ID⽣成系统:Leaf是美团开源的分布式ID⽣成器,能保证全局唯⼀性、趋势递增、单调递增、信息安全,⾥⾯也提到了⼏种分布式⽅案的对⽐,但也需要依赖关系数据库、Zookeeper等中间件。https://tech.meituan.com/2017/04/21/mt-leaf.html
附:
一条SQL语句在MySQL中如何执行的
一条SQL语句执行得很慢的原因有哪些
MySQL高性能优化规范建议
书写高质量SQL的30条建议