一、其实对于MySQL优化在初期需求分析和表设计的时候就已经开始了,首先要保证单条数据大小的控制,因为MySQL底层是16kb大小的内存页,如果单条数据大小是16kb,那么一个内存页就只能保存一条数据,这基本是白费劲,如果单条数据大小是1kb,那一个内存页可以存储16个数据,为什么要提到内存页呢,因为一个内存页也就是我们所说的一次IO,一次IO读取一个内存页。那么如何保证单条数据量的大小呢,比如我们要存储一个UUID,这个UUID是32位的,此时我们就要把它定死为32位,如果需要容错,可以扩展到33、34位,但一定不要浪费MySQL的存储空间,因为存储空间一旦大了,就会影响整个B+树的高矮胖瘦,因为B+树是高扇出性,B+树的所有节点,都是16kb大小的内存页,可以做一个简单的计算,比如B+树的根节点是16kb,那么它就会存储一个指针,指向第二层,每个指针都是16kb大小,第二层就有1170个左右的16kb大小的向下指针,第三层就有1170平方个16kb大小的内存页,再乘以16,也就是大概可以存储2000万条数据,如果单条数据是16kb,整个B+树也就能存储2000万除以16条数据,也没多少,所以开始的时候就要保证单条数据量的大小,比如性别字段中男、女,就可以用1和0去标志,第一可以提高检索效率,第二就是可以控制数据量的大小,这样可以保证同样高度的B+树可以存储最多的数据,三层B+树索引基本就是三次IO。
二、当表设计完了,开始增删改查了,我们就要对表的索引进行设计了,那怎么去设计索引是需要根据业务需求去进行的,比较常用的索引说三个吧,聚簇索引,辅助索引,覆盖索引。
聚簇索引:一张表只有一个,也就是主键id。
辅助索引:这个是我们自己创建的,每个辅助索引都有一个树。
覆盖索引:这里没有树。
在设计SQL语句的时候要避免使用select *,因为select *是无法避免走辅助索引和覆盖索引的,它要进行全表扫描拿到所有数据,只有聚簇索引的B+树里面的叶子节点有这些数据,首先要避免这个,但如果非要进行select * ,建议使用MySQL5.6的版本,因为这个版本里面有离散游的优化和ICP的优化,对select *的查询速度会快一些。
在说一下覆盖索引,在表索引设计的时候,如果有select n个字段,这n个字段都可以作为索引的话,就这样去设计,因为这样我们可以在辅助索引里面拿到要查询的数据,辅助索引里面含着主键索引和索引的值,这样可以避免回表的查询,这样查询的速度是很快的,这是对索引的理解。在书写SQL语句的时候要按照MySQL的执行计划去进行,要查看索引是否失效,因为在特定的环境下和特定的函数下边,索引会失效,也可以用explain+SQL去查看MySQL是怎么处理SQL语句的。
三、当数据量变大时,我们最简洁的操作就是partition分区,分区的操作要根据业务需求,可以根据日期分区,可以根据id范围分区,这都是可以的,当然也是有缺点的,就是单台MySQL服务器只支持1024个分区,当达到范围之后,就要考虑下一步调优,就是垂直拆分和水平拆分。
垂直拆分就是单表变多表,这个好处就像刚才说提到的,单条数据量越小,B+树的存储量越大,那么分区之后存储量也会越大,进而多个分区的存储量也会变得更大,但也是有一些缺点的,就是在我们进行垂直拆分的时候需要考虑到表的关联性,我们在MySQL进行数据查询的时候一旦有表关联的话,就要考虑他的性能,这个是需要测试的,最好的场景就是拆分出来的表都可以支撑特定的业务线,这就要看相对的业务选取,不同的业务也许有不同的设计方案。
在说一下水平拆分,当进行了垂直拆分和分区之后还是支撑不了数据的查询的话,这个时候就要进行水平拆分,比如某宝的订单一天有2000万条,这2000万条订单数据就要存储到2台不同的MySQL服务器中,一台存一半,这时需要用到一些算法,比如一致性hash算法,将不同的订单存储到不同的服务器中,此时用日期拆分就不行了,就要按整个业务需求,因为在极端的情况下会同时查询多个订单,不同的订单在不同的MySQL服务器中,也就会出现多个MySQL的查询,这种情况就要考虑到用哪个键值去划分他的水平拆分key,避免单条SQL查询多个MySQL的情况。
四、最后一个就是冷热备份,有一些无用的数据会占用较大的内存容量,这时要根据业务需求,当需求允许的情况下,对数据进行实时备份,来保证MySQL的存储量保持一个稳定状态。