【MySql学习笔记】Sql优化

优化Sql步骤

一、查看Sql执行频率

# 查询全局的执行情况
show global status like 'Com_______';
# 查询InnoDB的执行情况
show global status like 'Innodb_rows_%';

二、定位低效率的Sql

慢查询日志:设置执行时间,将超过时间的Sql记录在日志中。

show processlist:查看实时的Sql语句执行情况

三、explain分析执行计划

explain select * from t_role r, t_user u, user_role ur where r.id = ur.role_id and
u.id = ur.user_id ;

四、show profile分析Sql

# 查看MySql是否支持profile
select @@have_profiling;
# 查看profiling状态,0表示未开启
select @@profiling
# 开启profiling
set profiling = 1;
# 查看指令耗费的时间
show profiles;
# 查看时间耗费在了哪个阶段,query_id就是上面查询出来的语句的序号
show profile for query `query_id`

五、trace分析优化器执行计划

打开trace,设置格式为JSON,并设置trace最大能够使用的内存大小,避免解析过程中因为默认内存过小而不能够完整展示。

SET optimizer_trace="enabled=on",end_markers_in_json=on;
set optimizer_trace_max_mem_size=1000000;

执行Sql语句

select * from tb_item where id < 4;

检查information_schema.optimizer_trace就能够知道MySql是如何执行Sql

select * from information_schema.optimizer_trace\G;

Sql优化

插入大量数据[InnoDB存储引擎]

  • 主键顺序插入:导入的数据按照主键的顺序排列可以提高导入数据的效率,如果没有主键,系统将自动创建一个内部列作为主键,如果可以给表创建一个主键,就可以提交导入数据的效率。
  • 关闭唯一性校验:set unique_checks = 0,在导入数据结束之后执行set unique_checks = 1,恢复唯一性校验。

  • 手动提交事务:set autocommit = 0,导入数据后set autocommit = 1

优化insert语句

  • 需要插入多行数据的时候,使用多个值表的insert语句insert into test values(1, 'Tom'),(2, 'Cat'),(3, 'Jerry');

  • 在事务中进行插入

  • start transaction;
    insert into test values(1,'Tom'),(2,'Cat'),(3,'Jerry'); 
    commit;
  • 数据按照顺序插入

优化order by语句

  • 两种排序方式

    • 通过对返回的数据进行排序(filesort排序):不是通过索引直接返回排序结果的排序都是filesort排序。

    • 通过有序索引扫描直接返回有序数据(using index):不需要额外排序,操作效率高,查询的时候返回的字段是覆盖索引。

    • 多字段排序:要么全升序,要么全降序。查询的时候字段出现的顺序要和索引中出现的顺序相同。

  • 尽量减少额外的排序,通过索引直接返回有序数据,order by的顺序需要和索引顺序相同,order by的字段要么都是升序,要么都是降序,否则就会出现额外的排序。

  • filesort排序的优化

    • 两次扫描算法:MySql4.1之前使用这种方式。根据条件取出字段和指针信息,然后在排序区sort buffer中排序,如果sort buffer不够,那么就在临时表temprorary table中存储排序结果,完成排序之后根据行指针回表读取记录,该操作会导致大量随机I/O操作。

    • 一次扫描算法:一次性取出满足条件的所有字段,在排序区sort buffer中排序后直接输出结果集,排序的时候内存开销大,但是排序的效率比较高。

    • MySql通过比较系统变量max_length_for_sort_data的大小和Query语句取出的字段总大小,来判定使用哪种排序算法,如果max_length_for_sort_data更大,那么使用第二种优化之后的算法;否则使用第一种。

    • 可以适当提高sort_buffer_sizemax_length_for_sort_data系统变量,来增大排序区的大小,提高排序的效率。

优化group by语句

  • order by实际上也会进行排序操作,与order by相比,group by主要是多了排序之后的分组操作。如果分组的时候还使用了一些聚合函数,那么还需要聚合函数的计算,所以在group by的实现过程中,order by一样可以利用索引

  • 如果查询包含group by,但是用户想要避免排序结果的消耗,那么就可以使用order by null禁止排序。

  • explain select age,count(*) from emp group by age order by null; 
    # 第一个语句需要filesort,而order by null则不需要filesort

优化嵌套查询

  • 使用多表链接查询来替换子查询

优化or条件

  • or所连接的字段,每个字段都需要使用索引,不能使用复合索引。

  • 一般不常使用索引,通常使用union来替换or。

优化分页查询

  • 分页查询的时候,创建覆盖索引能够更好的提高性能。常见问题:limit 2000000,10,此时要排序前2000010条记录,然后返回2000000 - 2000010的记录,其他的记录丢弃,这样一来查询排序的代价就会很大。

  • 优化思路一:在索引上完成分页操作,最后根据主键关联回表查询所需要的其他列。

  • explain select * from tb_item t, (select id from tb_item order by id limit 20000, 10) a 
    where t.id = a.id;
  • 优化思路二:如果表中数据是主键自增的。

  • select * from tb_item id > 20000 limit 10;

使用Sql提示

  • 优化数据库的一种手段,通过人为的方式告诉数据库使用哪一个索引。

  • use index:查询语句中表名的后面添加use index(索引名称)来提供索引列表,这里只是提供参考,不强制使用索引。

  • ignore index:如果用户想让MySql忽略一个或者多个索引,可以在表名后面调价ignore index(索引名称)。

  • force index:强制MySql使用一个特定的索引,查询的时候在表名后面添加force index

posted @ 2021-09-27 22:46  菜鸭丶  阅读(55)  评论(0编辑  收藏  举报