MySQL优化(持续更新)笔记

发布于:2025-05-01 ⋅ 阅读:(23) ⋅ 点赞:(0)

一、insert优化 :

之前:项目通常是一条insert一条的执行,每一次都需要与MySQL进行建立连接进行网络传输,效率很低

现在:

1.- 批量插入(一条sql就行,一次500-1000)

可以与MyBatis联系起来如何优化我们之前写的语句

- 手动提交事务(MySQL默认执行一条就自动提交一次,这样频繁地开启提交效率也是非常低的,统一执行完再插入)

- 主键顺序提交事务

2.想要大量插入数据,使用insert性能太低,可以使用MySQL数据库提供的load指令来插入数据
将本地的数据(每条数据要符合一定规则的)直接加载到数据库文件当中,比如:每一个字段以逗号分割

执行一百万的数据,耗时16秒,如果是使用inser那么就需要十多分钟

注意需要按照主键顺序进行插入(效率高于乱序)

二、主键优化:

非叶子节点的页中存放的是行数据! 每个页中至少包含2行数据,根据主键排列

主键顺序插入:

    第一个数据页写满了,我再去申请写第二个数据页.....

    先在第一个页中插入数据(叶子节点),直到页满了,会申请第二个页继续插入数据.且页和页之间是双向指针!

主键乱序插入:

      主键乱序插入的情况下,可能会发生[页分裂]现象(50这个叶子节点并不会在第三页插入,而是在47后面,因为47后面还有一点空间)

50在第一页会想插入,那么首先将第一页的后百分之五十数据分裂开,将这些数据分配到第三页中,然后将50要插入的数据放到最后(比较耗性能)

页合并(当删除某一个数据,并不会真正从磁盘去除,而只是做了标记,如果被标识,就允许其他叶子结点声明使用,当达到一定的阈值的时候,就会去查看左右相邻的页看是否有合并的可能性
左边数据页满了,且没有标识删除状态,所以合并不了,再看右边的数据页,还有百分之50处于空闲,3号的数据移动到2号
在创建表或者是创建索引的时候我们可以去指定MERGE THRESHOLD

主键设计原则:

- 满足业务需求的情况下,尽量降低主键的长度.(在二级索引中叶子节点挂的是记录的主键,如果主键过长会大量浪费磁盘IO)
- 尽量使用auto_increment自增主键,来保证主键顺序插入(乱序插入容易导致"页分裂"以及"页合并"现象,虽然顺序插入可能也会但是频率会比较低!)
- 主键尽量使用自然主键+单一主键.而不要选择业务主键+复合主键.
- 尽量减少对主键的修改.一般主键都是一条记录在一个表中的唯一标识,会去动到索引的组织结构

三、order by优化:

注意:Using index性能高,尽量优化成Using index

以下查询字段不在索引中(没有覆盖索引),可能会导致回表操作(查询的字段不包含department_id),从而产生Using Filesort,降低了性能。

效率相对较低,查询的字段没有包含该部门ID,只有员工ID,员工名称,导致查询的时候走Using FileSort.(我这里已经加了该字段索引

改进:现在走Using index,通过索引返回有序数据 emplyee_id,emplyee_id是该索引(叶子结点)下面挂的数据查询的department_id就是索引字段的值,就不需要再额外查询

现在我创建一个复合索引(项目的话,一般建议采用复合索引)

默认两个字段都是升序:(asc,没有指定的话默认都是asc),还是走Using Index  

两个字段都是倒序:反向扫描索引,然后走Using Index,性能也比较好

注意:以下违背了最左前缀法则,在创建索引的时候 department_id是排在第一位,不能在查询的时候直接跨域先排序salary

注意:我们在创建索引的时候,如果没有指定顺序,默认都是升序往后走,先按照depart升序,然后再按照sal.如果现在是要按照sal要倒序,一个升序,一个倒序,还需要额外的创建排序(复合索引),否则走Using fileSort

改进(解决):

先查看一个整张表的索引结构
collection:A默认按照升序,此时salary需要额外去排,如何去优化???

我们再次创建一个复合索引,这次的索引不走两个默认都为升序,而是一个升序一个倒序,规避了Using Filesort出现

查看结果:

注意: 上面都是满足覆盖索引,才会在索引的条件下直接有序排列

总结:
* 根据排序字段建立合适的索引,多字段排序时,也遵守最左前序法则!
* 尽量使用覆盖索引
* 多字段排序,一个升序一个降序,注意创建联合索引的规则(asc / desc)

补充:

explain select id,age,phone from tb_user order by phone,age  违反了最左前缀法则,会fillsort!!!

group by优化:需要建立适当的索引来提升,分组底层其实也是排序,所以尽量给group by后面字段进行加索引!在未添加索引时的分组搜索,默认走Using temporary 效率比较低
我们一般添加索引的时候,比较多用于复合索引

创建联合索引

有用到索引,但是也用到了临时表,效率比较低

分组遵循最左前缀法则 走Using Index

这里也满足最左前缀法则

四、limit优化:

对limit来说,对于数据量大数据,越往后效率越低。耗时越大,到五百万条时,耗时甚至达到19.5s

limit的原理(重点):

  limit的原理:
    server层会调用存储引擎层提供的接口,查询出来所有数据,存储到server层的结果集中,并抛弃掉前面不需要的数据然后返回给客户端....
    limit 200000,10  ===>  需要调用引擎层的接口查询出来前200010条的所有数据(先调用接口查询出所有)并返回给server层,然后由server层再抛弃掉前200000条数据,只返回后10条給客户端....所以说从引擎层获取许多无用的数据然后又抛弃掉,这是非常耗时的!

1.先满足覆盖索引,将要查询的记录的ids集合查询出来(子查询,一会要根据ID进行连接)

2.然后将上面查询出来的表作为子表,进行子查询,这样走的是主键索引,会很快

3.那么从一开始耗时19.5秒提升到11.5秒

注意:limit 不适合大数据量

五、count优化:

   在InnoDB引擎中,在大数据量的情况下count()计数操作本身就是比较耗时的,因为需要扫描每一行记录,然后进行计数的累加!本身就比较耗时,其实这里是不方便优化的.如果要优化可以考虑自己计数!


count的几种用法:

1.我们可以自己计数,借助redis插入数据时,计数加1 ,删除时计数减一,比较繁琐。

2.count(主键):不用再判断是否为null,但也是需要把id先取出来才能累计

3.count(字段):先判断有没有not null  ,没有的话服务层还要额外的判断

4.count(1):  只要不是null,放个0,-1,1都可以,然后逐行累加,不会取值

5.count(*):专门针对优化,不会取值,直接累加

六、update优化:

MySQL事务隔离级别默认为行锁

两个事务
其中一个事务update数据的时候如果根据索引字段进行的更新,那么开启的就是行级锁.(这个时候我只针对我某一行的修改,我只锁住该行,其他事务操作自己的行,互不影响,互不干扰)
如果是根据非索引字段更新,那么就是开启表锁了(此时其他事务在操作的时候直接卡住,必须等待该锁被释放才能执行)!别的事务就不能更新了!!!

我们update数据的时候一定要根据索引字段进行更新,不然行级锁就要被升级为表锁了!!!
成为表锁了,我们的并发性能就会降低!!!


网站公告

今日签到

点亮在社区的每一天
去签到