SQL性能分析和优化


SQL性能分析

进行 SQL 优化首先需要了解 sql 语句执行的情况,下面有三种分析方式。

下面三种重要性不高,还是主要看 explain:Mysql执行计划分析 | KTnoobStation (gitee.io)

查看执行频次

通过模糊查询语句判断当前数据库哪些操作是使用更多的(一般是查询最多)

慢查询日志

慢查询日志会记录所有执行时间超过指定参数的 sql 语句。

默认未开启,可在配置文件中开启。

show profiles

主要可以记录所有 sql 语句在各个阶段的所花费的时间。

初始化,执行等等的过程耗费的时间。

SQL性能优化

包括插入优化、主键优化、order by 排序优化、group by 分组优化、limit 分页优化、count 计数优化、update 更新优化。

为避免长篇大论,简要概括每一条

insert 插入优化

即在大量数据插入的场景怎么优化的问题。

  1. 尽量采用批量插入,减少 insert 语句调用次数,如果量太多,可以分批次的批量查询。
  2. 手动提交事务,减少事务的开启和关闭次数。

    执行一系列 insert 语句前开启事务,结束后手动提交。

  3. 按照主键的顺序插入。(涉及主键优化)

    在待插入数据量极大的时候,可以采用 Mysql 的 load 命令(从文件直接加载到数据库表中)。

主键优化

聚集索引一般都是根据主键建立的,因此主键优化实际上就是优化聚集索引的建立。

  1. 插入数据时,尽量按照顺序插入,如数据库自增主键 AUTO_INCREMENT;

    即插入时的数据主键值要是有序的,否则会产生页分裂指针重指向的现象,导致效率下降。

    页分裂,涉及到 InnoDB 的底层存储结构。参考 InnonDB架构和事务原理

  2. 在满足业务要求的前提下,降低主键的长度。

Order By 排序优化

尽量将已经存在有序索引的字段作为排序字段,这样可以避免排序操作,直接按照索引顺序返回数据。

建立索引时可以指定该字段的顺序,create index index_name on table_name(age asc) 联合索引同理,但是要注意使用 order by 命令时指定的顺序要和创建索引时的顺序相同,否则索引失效,还会走 filesort 。

  • 通过 explain 命令得到的 extra 中可能会提示 using filesort 即表示读取到数据后,会在排序缓冲区 sort buffer 先排序,后面才会返回数据。
  • 而使用索引就是 using index,不需要排序。

Group by 分组优化,也是尽量使用索引作为分组字段。否则会造成临时表的创建,导致效率降低;对应 using temporal

limit 分页查询优化

limit 分页语法:select * from table_name limit 0, 10; 指取第一条数据开始的前10 条数据。

会出现的问题

在大数据量情况下,比如查询第 5000000 以后的前 10 条数据,会特别慢。

因为 limit 5000000, 10 ,数据库需要排序前 5000010 条记录并只返回这 10 条数据,其他查询记录会丢失。

优化方式

使用覆盖索引 + 子查询。比如查询已经存在的聚集索引(或其他的覆盖索引),select id from table_name order by id limit 5000000, 10; 查询到这些 id 之后,外面再套一个父查询(根据 id 查数据),这样就可以极大减少需要查询的数据量,以提高效率。

例:select s.* from tb_sku s, (select id from tb_sku order by id limit 9000000,10) a where s.id = a.id;

count 计数优化

count 计数语法:select count(*) from table_name

基于引擎实现产生的问题

MyIsam 引擎会将一个表的行数存在磁盘中,因此使用 count 效率很高。
InnoDB 引擎是将数据读出来,然后再累计计数。

Count 的累计计数有几种情况:

  • count (*) ,记录总行数,由于不取具体数据,只是计数,效率最高
  • count (具体字段),取具体字段值,如果没加 NOT NULL 约束则判断是否为空 NULL,如果不是则按行计数+1
  • count (主键),取主键值,按行直接累加(主键一定非空)

InnoDB 引擎对count计数做了优化,会选用数据量较小的非聚簇索引进行统计。所以效率:count(*) ≈ count(常量) > count(id) > count(字段)

两种引擎在大数据量的情况下,效率差距巨大。

优化方式

尽量使用 count (*), 效率最高。

可参考掘金文章:MySQL select count(*)计数很慢,有没有优化方案? - 掘金 (juejin.cn)

Update 更新优化

倒也不是优化,但是要规避一些操作;比如更新时,条件中尽量使用建立了索引的字段

原因

  • 当条件字段为有索引的字段,如主键值聚集索引或非聚集索引,开启事务后,Mysql 只会给这一行索引的数据加“行级锁”,这时候其他事务对这个表的其他数据更新或其他操作不会被阻塞。
  • 当条件字段无索引,Mysql 会给这个表加“表级锁”,其他事务对该表的操作会被阻塞导致并发性能下降。

总结

擅用索引( ̄︶ ̄*))


文章作者: KTpro
版权声明: 本博客所有文章除特別声明外,均采用 CC BY 4.0 许可协议。转载请注明来源 KTpro !
  目录