mysql 子查询_详解mysql数据库性能优化实验--从两个sql来体会子查询的优化效果...

概述

需求:取出内部员工组(data_type=0)下的用户编号(user_id),用户名称(user_name)、用户密码( PASSWORD_ENCRYPTED) , 并 按 照 转正日期 的 时间(regul_date)来进行倒序排列,取出前 20条。

这里大家可以考虑下如果是你,会怎么去实现?


方案选择

方案1:

SELECT s.user_id, s.user_name, s.PASSWORD_ENCRYPTED FROM hr_employee h,sys_user s WHERE h.data_type = 0 AND h.EMPLOYEE_CODE = s.EMPLOYEE_CODE ORDER BYh.regul_date DESC  LIMIT 1000,20

方案2:

SELECT s.user_id, s.user_name, s.PASSWORD_ENCRYPTED FROM ( SELECT EMPLOYEE_CODE FROM hr_employee WHERE data_type = 0 ORDER BY regul_date DESC LIMIT 1000, 20 ) h, sys_user s WHERE h.EMPLOYEE_CODE = s.EMPLOYEE_CODE

执行计划对比分析

方案1:

45a0e6f23c2143e1bb863f8990c2e0e0.png

解决方案一中的执行计划显示 MySQL 在对其中一个参与 Join 的表(sys_user)利用到了索引,hr_employee表走了全表扫描(其实也可以弄索引),在参与 Join 前 hr_employee表通过 Where 过滤后的结果集与 user 表进行 Join,最后通过排序取出Join 后结果的“limit 1000,20”条结果返回。

方案2:

f1267e44b1de72cbe98c3fa7fd4b893b.png

解决方案二的 SQL 语句利用到了子查询,所以执行计划会稍微复杂一些,首先可以看到sys_user表和解决方案1一样都利用到了索引(所使用的索引也完全一样),执行计划显示该子查询以hr_employee表为驱动,也就是先通过employee_code(工号)进行过滤并马上进行这一轮的结果集排序,然后取得了 SQL 中的“limit 1000,20”条结果,最后与sys_user 表进行 Join,得到相应的数据。

通过比较两个解决方案的执行计划,可以看到解决方案一中需要和sys_user表参与Join的记录 数, MySQL 通过统计数据估算出来是8506,也就是通过 hr_employee表返回的所有满足data_type=0的记录数(系统中的实际数据是20000)。而第二种解决方案的执行计划中,sys_user表参与Join的数据就只有850条,可以看到两者相差很大,所以第二种解决方案明显优于第一种解决方案。


SQL 实际执行的profile对比

打开 profiling 功能,然后分别执行两个解决方案的 SQL 语句,由 于SQL语句执行所消耗的最大两部分资源就是IO和CPU,所以这里仅列出BLOCK IO和 CPU两项 profile 信息,涉及sql如下

--开启profiling功能及历史条数SET PROFILING=1;SET PROFILING_HISTORY_SIZE=1000;SELECT s.user_id,s.user_name,s.PASSWORD_ENCRYPTED FROMhr_employee h,sys_user s WHERE h.data_type = 0 AND h.EMPLOYEE_CODE = s.EMPLOYEE_CODE ORDER BY h.regul_date DESC LIMIT 1000,20;SELECTs.user_id,s.user_name,s.PASSWORD_ENCRYPTED FROM( SELECT EMPLOYEE_CODE FROM hr_employee WHERE data_type = 0 ORDER BY regul_date DESC LIMIT 1000, 20 ) h,sys_user s WHEREh.EMPLOYEE_CODE = s.EMPLOYEE_CODE;--查看profile信息show profiles;show profile CPU,BLOCK IO for query 329;show profile CPU,BLOCK IO for query 336;
149f474fa7a97469dbd043ec4532881c.png
5485b5ac3d5a2fa74fe5f7be8edf62a3.png
878b9214b65c8b1c087c0ef82b1cd793.png

观察两条 SQL 执行中的 IO 消耗,两者区别就在于“Sorting result”,从前面执行计划的对比可以知道两个解决方案的排序过滤数据的时机不一样,排序后需要取得的数据量一个是8506,一个是850,正好和这里的 profile 信息吻合,第一种解决方案的 “Sorting result”的 IO 值是第二种解决方案的将近3倍。


结论:

通过上面两条功能完全相同的 SQL 语句的执行计划分析,以及通过实际执行后的profile 数据的验证,都证明了第二种解决方案优于第一种解决方案。

觉得有用的朋友多帮忙转发哦!后面会分享更多devops和DBA方面的内容,感兴趣的朋友可以关注下~

28fa8f60e2a209f69cb0105eb7691019.gif
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
2008数据库实验 1.SQL SEVER 2000的系统工具、使用交互方式建库、建表 2.T—SQL的简单查询、连接查询 3.子查询及组合 4.数据控制、数据导入/导出、数据备份和恢复 实验1 SQL SEVER 2000的系统工具、使用交互方式建库、建表实验 实验目的和要求:了解SQL SEVER 2000的功能及组成,熟练掌握利用SQL SEVER 2000企业管理器和查询分析器创建数据库、表、索引和修改表结构及向数据库输入数据、修改数据和删除数据的操作方法和步骤,掌握定义数据约束条件的操作。 实验内容和步骤: (1)熟悉SQL SEVER 2000的界面和操作。 (3)熟悉企业管理器和查询分析器的界面和操作。 (3)创建数据库和查看数据库属性。 (4)创建表、确定表的主码和约束条件。 (5)查看和修改表的结构。 (6)向数据库输入数据,观察违反列级约束时出现的情况。 (7)修改数据。 (8)删除数据,观察违反表级约束时出现的情况。 实验2 T—SQL的简单查询、连接查询 实验目的和要求:,了解SQL语句的数据定义与数据更新功能,了解SQL语句的查询功能,掌握SQL中的数据定义语句的用法,熟练掌握SQL中的插入、修改和删除语句的操作,熟练掌握使用SQL语句进行数据库的简单查询、连接查询实验内容和步骤: (1)在SQL SEVER 2000的查询分析器里,用SQL语句建库、建表并插入记录。 (2)修改表结构,包括修改属性列的数据类型,增加新的属性列,删除已有的属性列。 (3)使用单个元组和多元组插入。 (4)简单查询操作,包括投影、选择、数据排序、模糊匹配查询等。如果结果不正确,要进行修改,直至正确为止。 (5)连接查询操作,包括等值连接、自然连接、一般连接、自身连接、外连接。 实验3 子查询及组合 实验目的和要求:了解SQL语句的查询功能,理解视图的概念。熟练掌握使用SQL语句进行数据库的嵌套查询及组合查询的操作;掌握视图创建语句和视图的使用方法,加深对视图作用的理解。 实验内容和步骤: (1)在DBMS的交互式环境里,用SQL语句建库、建表并插入记录。 (2)使用In、比较符和Exists操作符进行嵌套查询操作。 (3)分组查询,包括分组条件表达、选择组条件表达的方法。 (4)集合查询。 (5)使用视图创建语句建视图,通过视图查询数据 (6)带子查询的修改和删除 (7)通过视图修改和删除数据 实验4 数据控制、数据的导入/导出、数据库备份和恢复 实验目的和要求:掌握数据控制(安全性)的方法,了解SQL SEVER 2000的数据备份和恢复机制,掌握SQL SEVER 2000中数据库备份和恢复的方法。 实验内容和步骤: (1)使用SQL对数据进行安全性控制,包括授权和权利收回。 (2)查看授权和权利收回后的结果 (3)SQL SEVER 2000工具对表中的数据导出到其它格式的文件。 (4)将其它格式的文件数据导入到数据库中。 (5)使用SQL SEVER 2000工具创建一个数据库的备份(海量备份、增量备份)。 (6)使用SQL SEVER 2000工具及所创建的数据库备份恢复这个数据库
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值