文章目录

  • 看完本篇文章你能学到什么?
  • SQL语句优化
    • 1.1 排序优化
      • 1.1.1 索引优化
      • 1.1.2 算法优化
      • 1.1.3 排序优化建议
    • 1.2 分组优化
    • 1.3 分页优化
      • 1.3.1 分页优化一
      • 1.3.2 分页优化二
    • 1.4 表优化
      • 1.4.1 数据空洞
      • 1.4.2 optimize优化表
        • 1.4.2.1 InnoDB表优化
        • 1.4.2.2 MyISAM表优化
    • 1.5 总结
    • 好了,本篇就说到这里了,看完觉得有帮助的童鞋记得点赞!点赞!点赞!(重要的事情说三遍!)

看完本篇文章你能学到什么?

1、排序优化

2、分组优化

3、分页优化

4、表优化

SQL语句优化

本篇内容全部围绕SQL语句如何优化,告诉大家实际的优化手段(落实到代码),不绕弯子。

注: 阅读本篇文章需要具备执行计划、索引失效等相关知识。

  • 创建一张测试表,用于后期测试使用:
CREATE TABLE `userinfo` (`id` int(10) NOT NULL COMMENT '用户id',`username` varchar(50) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '用户名',`age` int(3) NULL DEFAULT NULL COMMENT '年龄',`phone` varchar(15) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '手机号',`gender` char(1) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '性别: ‘0’-男   ‘1’-女',`desc` text CHARACTER SET utf8 COLLATE utf8_general_ci NULL COMMENT '自我介绍',`register_time` datetime(0) NULL DEFAULT NULL COMMENT '注册时间',`login_time` datetime(0) NULL DEFAULT NULL COMMENT '上一次登录时间',`pic` varchar(250) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '头像地址',`look` int(10) NULL DEFAULT NULL COMMENT '查看数',PRIMARY KEY (`id`)
) ENGINE = InnoDB CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Compact;

1.1 排序优化

1.1.1 索引优化

在排序时,尽量使用索引字段进行排序,否则会采用文件排序(filesort),效率低。

  • 根据普通字段排序:
show index from userinfo;                                -- 查询当前表有多少索引explain select * from userinfo order by username;      -- 根据普通字段排序

  • 给排序字段创建索引:
create index idx_name on userinfo(username);                         -- 创建索引explain select * from userinfo order by username;                        -- filesortexplain select username from userinfo order by username;             -- Using indexexplain select username,age from userinfo order by username;          -- filesort

根据索引字段排序,之后查询的数据必须是索引数上的数据,不可查询额外字段,更不能查询全表字段

其实这一段算是废话来着,谁不知道使用索引能够加快速度啊!还用你说???

好吧,其实这里只想跟你说一个东西:文件排序

就是上面看到的Using filesort其实filesort并不代表MySQL使用到了文件进行排序,文件排序只是一种算法,我们习惯把它翻译成"文件排序"而已。一旦看到了filesort,那么就意味着效率很低了。

1.1.2 算法优化

MySQL在排序时,如果不能够借助索引直接完成排序,那么将会使用文件排序(filesort)。如果使用了filesort,那么MySQL会将数据在内存中进行排序,排序内存由系统变量sort_buffer_size控制。默认为256KB。

注意,排序缓冲区是每个线程是独享的。因此设置太大在并发量高的情况下会消耗MySQL服务器大量内存。

MySQL的排序算法分为两种:

  • 1)多扫描排序:首先根据排序条件取出排序字段的行指针信息,然后在排序缓冲区(sort_buffer_size)中进行排序。排序完毕之后会根据排序缓冲区中的行指针回表查询。操作磁盘次数多(两次),效率较低。
  • 2)单扫描排序:根据条件取出所有字段的信息(不仅仅是排序字段),然后在排序缓冲区中进行排序,排序完毕之后直接将结果集返回。这一步对排序缓冲区要求比较大,但排序效率高。

1、如果排序缓冲区大小不足,那么则会采用临时表(temporary table)存储排序结果。之后临时表的行指针信息重新回表查询记录。效率低

2、每个线程都有自己独自的排序缓冲区,如果排序缓冲区设置过大,会浪费内存。

因此sort_buffer_size的大小根据你们需要排序的数据大小来决定。太大浪费内存,太小造成临时表的使用,降低效率。

那MySQL到底采用哪种排序算法?

MySQL4.1版本之前只有多扫描排序算法,单扫描排序是MySQL4.1版本推出的新排序算法,用于优化多扫描排序。MySQL主要根据系统变量max_length_for_sort_data的大小和此次Query语句所取出的所有字段大小之后对比,如果max_length_for_sort_data大,则使用单扫描排序,反之使用多扫描排序。

  • 查询max_length_for_sort_data的默认值:
select @@max_length_for_sort_data;

max_length_for_sort_data默认1KB。

1.1.3 排序优化建议

如果是排序场景很多,且每次排序的数据量大。建议使用单排序,即max_length_for_sort_data调的尽可能大,并且保证每次排序的数据都在sort_buffer_size大小之内。

  • 创建举例:

有些网站业务不怎么复杂,专门做统计用的,经常需要升序/降序,并且数据量大。
当然了,上面的场景那些前端UI框架都能帮我们做好,根本不需要发送请求到后台,注意,我说的是类似场景

1.2 分组优化

在MySQL中group by语句会触发一次默认的order by排序操作,造成不必要的性能浪费。我们可以手动的禁止分组操作带来的排序操作。

  • 准备测试表:
CREATE TABLE `student`  (              -- 学生表`id` int(11) NOT NULL,`name` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL,`age` int(11) NULL DEFAULT NULL,`c_id` int(11) NULL DEFAULT NULL,      -- 班级idPRIMARY KEY (`id`) USING BTREE
) ENGINE = InnoDB CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Dynamic;CREATE TABLE `class`  (                 -- 班级表`id` int(11) NOT NULL,`name` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL,PRIMARY KEY (`id`) USING BTREE
) ENGINE = InnoDB CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Dynamic;INSERT INTO `class` VALUES (1, 'Java01');
INSERT INTO `class` VALUES (2, 'Java02');INSERT INTO `student` VALUES (1, '小红', 20, 2);
INSERT INTO `student` VALUES (2, '小军', 25, 2);
INSERT INTO `student` VALUES (3, '小明', 24, 1);
INSERT INTO `student` VALUES (4, '小龙', 19, 2);
INSERT INTO `student` VALUES (5, '小蓝', 22, 2);
INSERT INTO `student` VALUES (6, '小刚', 25, 1);
  • 根据班级id(c_id)计算每个班级平均年龄:
mysql> select avg(age),c_id from student group by c_id;
+----------+------+
| avg(age) | c_id |
+----------+------+
|  24.5000 |    1 |
|  21.5000 |    2 |
+----------+------+
2 rows in set (0.00 sec)mysql>

发现默认根据c_id排序了。

  • 如果我们自己手动去除排序结果应该是这样的:
mysql> select avg(age),c_id from student group by c_id order by null;
+----------+------+
| avg(age) | c_id |
+----------+------+
|  21.5000 |    2 |
|  24.5000 |    1 |
+----------+------+
2 rows in set (0.00 sec)mysql>
  • 查询如下两个SQL的执行计划:
explain select avg(age),c_id from student group by c_id;explain select avg(age),c_id from student group by c_id order by null;

发现每次的group by 分组操作都会触发一次默认的排序操作,如果我们没有这样的需求,无疑是增加了SQL语句的响应时间

1.3 分页优化

通常使用分页查询是来提高我们的查询效率的,因为通常用户不希望一下子查询到那么多的数据,一般是查询前几条数据,此时的分页效率会比较高。但是有时候在分页查询会遇到一个比较尴尬的问题,那就是limit N,10,即前面跳过N多条记录,只查询N多条记录的后面几条记录。如果N的值非常大,那么效率必然就会很低。

  • 此时数据库有300W记录:
select count(*) from userinfo;

  • 假设我们需要查询2900000-2900010记录:
explain select * from userinfo limit 2900000,10;         -- 获取sql的执行计划select * from userinfo limit 2900000,10;                   -- 执行sql,查看消耗的时间

从执行计划可以看出,进行了全表扫描

花费的时间为:

显然,效率非常低。

1.3.1 分页优化一

我们可以借助索引,在索引上面排序,然后通过索引关联表查询。

explain select * from userinfo u1,(select id from userinfo order by id limit 2900000,10) t where u1.id=t.id;


查看执行消耗时间:

1.3.2 分页优化二

如果id是顺序排列的话,我们可以先根据id进行排序,然后取后面10条。

explain select * from userinfo where id>2900000 limit 10;

  • 查看执行消耗时间:

1.4 表优化

1.4.1 数据空洞

当我们对数据库表进行删除(delete)时,这些行只是被标记为“已删除”,而不是真的从索引中物理删除了,因而空间也没有真的被释放回收。而这些被标记的行就是数据空洞。

我们进入/var/lib/mysql/${db_name}目录下查看当前数据库的一些磁盘存储信息。

300W记录大概花了536M的空间。

  • 我们删除200W数据再次查看磁盘占用:
start transaction;                           -- 控制在一个事务中(效率高)delete from userinfo where id > 1000000;commit;

再次查看磁盘占用空间,发现还是536M。并没有释放空间。

  • 查看表的状态信息:
mysql> show table status like 'userinfo'\G;
*************************** 1. row ***************************Name: userinfoEngine: InnoDBVersion: 10Row_format: CompactRows: 1110488Avg_row_length: 492Data_length: 547356672
Max_data_length: 0Index_length: 0Data_free: 99614720Auto_increment: NULLCreate_time: 2020-06-04 20:28:45Update_time: 2020-06-04 20:32:59Check_time: NULLCollation: utf8_general_ciChecksum: NULLCreate_options: row_format=COMPACTComment:
1 row in set (0.00 sec)

其中Data_free就是碎片(空洞)的数量

1.4.2 optimize优化表

当表中存在有大量的数据空洞时,我们可以使用optimize命令来优化表。即删除数据空洞。

1.4.2.1 InnoDB表优化

InnoDB表优化后会做一个重新构建索引+分析的一个过程。因为我们知道InnoDB引擎将数据与索引是放在一个文件中的,名为.idb,对数据进行整理后,必定会对索引造成影响。而MyISAM是将数据与索引文件分开存储的(.MYD、.MYI),因此MyISAM整理空洞不会对索引造成影响。

  • 执行表优化操作:
optimize table userinfo;

InnoDB表优化后,还会对表中的索引进行重构分析。因此在同等数量的碎片整理,InnoDB花费时间比Myisam表要多一点。

  • 再次查看表,发现占用磁盘空间变小。

1.4.2.2 MyISAM表优化

  • 创建一张MyISAM表:
CREATE TABLE `userinfo_myisam` (`id` int(10) NOT NULL COMMENT '用户id',`username` varchar(50) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '用户名',`age` int(3) NULL DEFAULT NULL COMMENT '年龄',`phone` varchar(15) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '手机号',`gender` char(1) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '性别: ‘0’-男   ‘1’-女',`desc` text CHARACTER SET utf8 COLLATE utf8_general_ci NULL COMMENT '自我介绍',`register_time` datetime(0) NULL DEFAULT NULL COMMENT '注册时间',`login_time` datetime(0) NULL DEFAULT NULL COMMENT '上一次登录时间',`pic` varchar(250) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '头像地址',`look` int(10) NULL DEFAULT NULL COMMENT '查看数',PRIMARY KEY (`id`)
) ENGINE = MyISAM CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Compact;
  • 编写存储过程,批量插入300W数据:
CREATE PROCEDURE `test_myisam`(count int)
begindeclare i int default 1;while i<=count do INSERT INTO userinfo_myisam values(i,uuid(),CEILING(RAND()*90+10),FLOOR(RAND()*100000000000),round(FORMAT(rand(),1)),uuid(),now(),now(),uuid(),CEILING(RAND()*90+10));set i=i+1;end while;
endcall test_myisam(3000000);           -- 插入300W数据
  • 删除200W数据:
delete from userinfo_myisam where id>1000000;
  • 执行表优化:
optimize table userinfo_myisam;

花费2.65s,比InnoDB效率高,因为InnoDB需要重新构建索引。

再次查看表磁盘占用情况,发现占用空间减少。

1.5 总结

总结本篇文章的重要几点:

  • 1、牢记排序优化的两个参数:sort_buffer_sizemax_length_for_sort_data
  • 2、分组操作默认会做一次排序操作,如果没有这个需求建议关闭(order by null)。
  • 3、分页优化参考具体SQL语句。
  • 4、表空洞优化

SQL优化很多方面是索引、锁、参数调优方面的优化,其中锁和索引的优化可以明显的提高SQL语句的查询速度,参数方面的优化则可以帮助我们搭建一个稳定的、高性能、高可用的MySQL集群架构,由于索引、锁、参数调优方面牵扯知识太广,本篇不做讲解。

好了,本篇就说到这里了,看完觉得有帮助的童鞋记得点赞!点赞!点赞!(重要的事情说三遍!)

SQL语句优化(落实到代码,不绕弯子)相关推荐

  1. 【腾讯面试题】SQL语句优化方法有哪些?

    SQL语句优化 性能不理想的系统中,除了一部分是因为应用程序的负载确实超过了服务器的实际处理能力外,更多的是因为系统存在大量的SQL语句需要优化. 为了获得稳定的执行性能,SQL语句越简单越好.对复杂 ...

  2. sql 一个字段在另外一个表没出现_都9012年啦,不懂得这些SQL语句优化,你是要吃大亏的...

    引言 数据库的性能优化技术一直是个老生常谈的问题,不管是MySQL.SQL Server还是Oracle. 对于我们IT开发人员和运维人员,掌握常用的SQL 优化语句是非常必要的,它可以使你的工作变得 ...

  3. mysql高效sql语句_高效SQL优化 非常好用的SQL语句优化34条

    高效SQL优化 非常好用的SQL语句优化34条 相关软件相关文章发表评论 来源:2011/2/13 9:38:43字体大小: 作者:佚名点击:576次评论:0次标签: 类型:电子教程大小:8.5M语言 ...

  4. sql like 多个条件_都9012年啦,不懂得这些SQL语句优化,你是要吃大亏的

    引言 数据库的性能优化技术一直是个老生常谈的问题,不管是MySQL.SQL Server还是Oracle. 对于我们IT开发人员和运维人员,掌握常用的SQL 优化语句是非常必要的,它可以使你的工作变得 ...

  5. 秋色园QBlog技术原理解析:性能优化篇:打印页面SQL,全局的SQL语句优化(十三)...

    文章回顾: 1: 秋色园QBlog技术原理解析:开篇:整体认识(一) --介绍整体文件夹和文件的作用 2: 秋色园QBlog技术原理解析:认识整站处理流程(二) --介绍秋色园业务处理流程 3: 秋色 ...

  6. 【转】sql语句优化工具LECCO SQL Expert

    软件说明: 更优更快 人工智能自动SQL优化----------http://www.sina.com.cn 2001/12/12 17:48 中国电脑教育报文/SQL爱好者 所谓SQL,就是指Str ...

  7. MySQL数据库:SQL语句优化

    数据库最常用的优化方式有:SQL语句和索引.数据库表结构.系统配置.硬件. 优化效果:SQL语句和索引 < 数据库表结构 < 系统配置 < 硬件,成本也是递增的. 优化方法 设计符合 ...

  8. SQL优化SQL语句优化的目的

    sql的优化,要看优化什么,性能,效率,稳定性,安全性?每个方面都有很大的不同. 内容参见:https://blog.csdn.net/sinat_37464123/article/details/8 ...

  9. SQL语句优化之降龙十八掌

    sql 语句优化 一前言  客服业务受到SQL语句的影响非常大,在规模比较大的局点,往往因为一个小的SQL语句不够优化,导致数据库性能急剧下降,小型机idle所剩无几,应用服务器断连.超时,严重影响业 ...

最新文章

  1. python学习之掷骰子游戏
  2. 为类定义后构造函数的最小示例,使用 boost::signals2::deconstruct 作为它的工厂函数
  3. 使用 Github Pages 和 Hexo 搭建自己的独立博客【超级详细的小白教程】
  4. Google Protobuf 使用介绍
  5. 哈工大女孩学计算机毕业转行,2020考生切记,上985读这些专业,据说都是“坑”!...
  6. 定义blob类型_MySQL 数据类型
  7. VS 安装部署项目自解压程序解压后按顺序执行多个程序
  8. IOS Andriod 抖音无水印下载和快手无水印下载
  9. 网络路径结点回溯分析工具
  10. 5寸照片尺寸_证件照尺寸及更换背景颜色教程
  11. 人口普查数据有疑问???
  12. 计算机内存不足 程序无法运行,计算机内存不足处理方法
  13. 〖毕业季|进击的技术er〗其他人都在缅怀青春、告诉你如何拿到 offer 、提高自己的技术栈、做未来规划路线,我偏要反其道而行、告诉你们一个不一样的技术er的职场成长。
  14. 别再逐帧扒电影了 生活中处处都有彩蛋!
  15. leet70:爬楼梯
  16. 计算机用户删除怎么找回,电脑不小心删除的数据怎么找回
  17. unity入门API————最常用的基类总结
  18. 自己封装的一个JS分享组件
  19. 供应链信息系统建设思路
  20. 基于javaee地铁人事管理系统的设计与实现

热门文章

  1. GPU和显卡是什么关系?GPU会取代CPU吗?
  2. linux 360wifi ap热点,rk3288 ap6335 linux下的wifi 热点功能使用
  3. 网红扎推背后的映客:78个内容审核人员把关3680万主播
  4. mysql的存储引擎有哪些 区别是什么_MySQL 存储引擎有哪些?区别是什么?
  5. 20年来最优秀游戏处理器!AMD锐龙7 7800X3D首发评测:大幅超越i9-13900KS
  6. linux zip压缩和unzip解压缩命令
  7. Orleans 2.0 官方文档 —— 开发一个Grain
  8. 联合主键的用法及注意事项
  9. 阿里云盾导致 cgroup2 cpu 控制器丢失的坑
  10. Network Architecture网络架构