1. MySQL中主要的存储引擎
MyISAM是MySQL官方提供的存储引擎,其特点是支持全文索引,查询效率比较高,缺点是不支持事务、使用表级锁。InnoDB在5.5版本后成为了Mysql的默认存储引擎,特点是支持ACID事务、支持外键、支持行级锁提高了并发效率。TokuDB是第三方开发的开源存储引擎,有非常快的写速度,支持数据的压缩存储、可以在线添加索引而不影响读写操作。但是因为压缩的原因,TokuDB非常适合访问频率不高的数据或历史数据归档,不适合大量读取的场景。
2. MySQL中的锁
表锁、行锁、共享锁、排它锁。
MyIASAM使用表级锁,InnoDB使用行级锁。表锁开销小,加锁快,不会出现死锁;但是锁的粒度大,发生锁冲突的概率高,并发访问效率比较低。行级锁开销大,加锁慢,有可能会出现死锁,不过因为锁定粒度最小,发生锁冲突的概率低,并发访问效率比较高。
共享锁也就是读锁,其他事务可以读,但不能写。MySQL可以通过Lock In Share Mode语句显示使用共享锁。
排他锁就是写锁,其他事务不能读取,也不能写。对于Update、Delete和INSERT语句,InnoDB会自动给涉及的数据集加排他锁,或者使用select for update显示使用排他锁。
3. 索引
索引可以大幅增加数据库的查询的性能,在实际业务场景中,或多或少都会使用到。
但是索引是有如下2个代价的:
a.需要额外的磁盘空间来保存索引
b.对于插入、更新、删除等操作由于更新索引会增加额外的开销
因此索引比较适合用在读多写少的场景。
3.1 MySQL索引类型
共分为5类:
- 唯一索引:就是索引列中的值必须是唯一的,但是允许出现空值。这种索引一般用来保证数据的唯一性,比如保存账户信息的表,每个账户的id必须保证唯一,如果重复插入相同的账户id时会MySQL返回异常。
- 主键索引:是一种特殊的唯一索引,但是它不允许出现空值。
- 普通索引:与唯一索引不同,它允许索引列中存在相同的值。例如学生的成绩表,各个学科的分数是允许重复的,就可以使用普通索引。
- 联合索引:就是由多个列共同组成的索引。一个表中含有多个单列的索引并不是联合索引,联合索引是对多个列字段按顺序共同组成一个索引。应用联合索引时需要注意最左原则,就是Where查询条件中的字段必须与索引字段从左到右进行匹配。比如,一个用户信息表,用姓名和年龄组成了联合索引,如果查询条件是姓名等于张三,那么满足最左原则;如果查询条件是年龄大于20,由于索引中最左的字段是姓名不是年龄,所以不能使用这个索引。
- 全文索引:前面提到了,MyISAM引擎中实现了这个索引,在5.6版本后InnoDB引擎也支持了全文索引,并且在5.7.6版本后支持了中文索引。全文索引只能在CHAR,VARCHAR,TEXT类型字段上使用,底层使用倒排索引实现。要注意对于大数据量的表,生成全文索引会非常消耗时间也非常消耗磁盘空间。
3.2 索引实现
索引实现共分4种形式:
- B+树实现:b+树比较适合用作’>’或’<’这样的范围查询,是MySQL中最常使用的一种索引实现。
- R-tree:是一种用于处理多维数据的数据结构,可以对地理数据进行空间索引。不过实际业务场景中使用的比较少。
- Hash:是使用散列表来对数据进行索引,Hash方式不像Btree那样需要多次查询才能定位到记录,因此Hash索引的效率高于B-tree,但是不支持范围查找和排序等功能.实际使用的也比较少。
- FullText:就是我们前面提到的全文索引,是一种记录关键字与对应文档关系的倒排索引。
4. MySQL的存储过程与函数
存储过程和函数都可以避免开发人员重复编写相同的SQL语句,并且存储过程和函数都是在MySQL服务器中执行的,可以减少客户端和服务器端的数据传输。
存储过程能够实现更复杂的功能,而函数一般用来实现针对性比较强的功能,例如特殊策略求和等。存储过程可以执行包括修改表等一系列数据库操作,而用户定义函数不能用于执行修改全局数据库状态的操作。
存储过程一般是作为一个独立的部分来执行,而函数可以作为查询语句的一个部分来调用。SQL语句中不能使用存储过程,但可以使用函数。
不过存储过程一般与数据库实现绑定,使用存储过程会降低程序的可移植性,应谨慎使用。
5. 新特性
可以了解MySQL8.0的一些新特性,例如默认字符集格式改为了UTF8;增加了隐藏索引的功能,隐藏后的索引不会被查询优化器使用,可以使用这个特性用于性能调试;支持了通用表表达式,使复杂查询中的嵌入表语句更加清晰;新增了窗口函数的概念,它可以用来实现新的查询方式。窗口函数与 SUM、COUNT等集合函数类似,但不会将多行查询结果合并,而是将结果放在多行中。即窗口函数不需要GROUP BY。
6. MySQL调优
一般MySQL调优有4个纬度:
- 针对数据库设计、表结构设计以及索引设置纬度进行的优化;
- 对业务中使用的SQL语句进行优化,例如调整Where查询条件;
- 对mysql服务的配置进行优化,例如对链接数的管理,对索引缓存、查询缓存、排序缓存等各种缓存大小进行优化;
- 对硬件设备和操作系统设置进行优化,例如调整操作系统参数、禁用Swap、增加内存、升级固态硬盘等等。
这四个纬度从优化的成本角度来讲,从上到下优化成本逐渐升高;从优化效果角度来看,从下到上优化的效果更高。
对于研发人员来说,前两个纬度与业务息息相关,因此需要重点掌握,后两个纬度更适合DBA进行深入学习,简单了解就好。下面介绍前两个纬度。
6.1 表结构和索引的优化
应该掌握如下6个原则:
- 第1个原则:要在设计表结构时,考虑数据库的水平与垂直扩展能力,提前规划好未来1年的数据量、读写量的增长,规划好分库分表方案。比如设计用户信息表,预计1年后用户数据10亿条,写QPS约5000,读QPS30000,可以设计按UID纬度进行散列,分为4个库每个库32张表,单表数据量控制在KW级别;
- 第2个原则:要为字段选择合适的数据类型,在保留扩展能力的前提下,优先选用较小的数据结构。例如保存年龄的字段,要使用TINYINT而不要使用INT;
- 第3个原则:可以将字段多的表分解成多个表,必要时增加中间表进行关联。假如一张表有4、50个字段显然不是一个好的设计;
- 第4个原则:是设计关系数据库时需要满足第三范式,但为了满足第三范式,我们可能会拆分出多张表。而在进行查询时需要对多张表进行关联查询,有时为了提高查询效率,会降低范式的要求,在表中保存一定的冗余信息,也叫做反范式。但要注意反范式一定要适度;
- 第5个原则:要擅用索引,比如为经常作为查询条件的字段创建索引、创建联合索引时要根据最左原则考虑索引的复用能力,不要重复创建索引;要为保证数据不能重复的字段创建唯一索引等等。不过要注意索引对插入、更新等写操作是有代价的,不要滥用索引。比如像性别这样唯一很差的字段就不适合建立索引;
- 第6个原则:列字段尽量设置为Not Null,MySQL难以对使用Null的列进行查询优化,允许Null会使索引、索引统计和值更加复杂。允许Null值的列需要更多的存储空间,还需要MySQL内部进行特殊处理。
6.2 SQL语句进行优化的原则
共分5个原则:
- 第1个原则:要找的最需要优化的SQL语句。要么是使用最频繁的语句,要么是优化后提高最明显的语句,可以通过查询MySQL的慢查询日志来发现需要进行优化的SQL语句;
- 第2个原则:要学会利用MySQL提供的分析工具。例如使用Explain来分析语句的执行计划,看看是否使用了索引,使用了哪个索引,扫描了多少记录,是否使用文件排序等等。或者利用Profile命令来分析某个语句执行过程中各个分步的耗时;
- 第3个原则:要注意使用查询语句是要避免使用Select *,而是应该指定具体需要获取的字段。原因一是可以避免查询出不需要使用的字段,二是可以避免查询列字段的元信息;
- 第4个原则:是尽量使用Prepared Statements,一个是性能更好,另一个是可以防止SQL注入;
- 第5个原则:是尽量使用索引扫描来进行排序,也就是尽量在有索引的字段上进行排序操作。