任务 4 对数据表进行多种查询并查看执行计划与消耗时间
任务目的
对测试表进行单表查询、多表关联查询,查看每种查询的消耗时间,阅读SQL语句对应的执行计划,理解执行计划意义。
任务步骤
1.开启PROFILE功能
开启MySQL PROFILE功能,用于查看SQL语句执行过程中的资源使用情况。
set profiling=1;2.进行单表查询
单表简单查询:id为9900的员工的工资。并查看该语句的执行计划与资源消耗。
1)查询id为9900的员工的工资。
SELECT id,salary FROM empsalary WHERE id=9900;2)查看该语句的执行资源消耗,此处注意,SHOW PROFILE;显示的是最后一个SQL语句的消耗时间。如果要指定之前运行过的某一条语句来查看,可以先从SHOW PROFILES;中记住目标SQL的编号(例如编号为3),然后SHOW PROFILE FOR QUERY 3即可查看到。
SHOW PROFILES;
SHOW PROFILE;可以看到总时间0.00352750秒,其中主要时间花费在Sending data步骤(0.003205秒),也就是时间主要消耗在数据本身的收集获取和发送。而其他的锁、解析等占用的时间比例很少。此处需要注意,同一条SQL多次运行,消耗时间不一定一致,因为语句的执行会受到数据库本身软硬件负载以及数据库本身优化器、统计信息等多重因素的影响。
3)查询该语句的执行计划。可以看到在关键的type一栏显示为ALL,即全表扫描。相当于对表中的所有数据扫描了一次,才获取到想要的结果。
EXPLAIN SELECT id,salary FROM empsalary WHERE id=9900;3.函数查询
进行结合函数转换的单表查询。仍然对工资表进行查询,但对数据和查询条件进行函数变换处理。
1)查询工号前三位为999的员工的工号和工资。需要使用substr对id进行截取,从第1位起,截取3位。
SELECT id,salary FROM empsalary WHERE substr(id,1,3)=999;2)显示时间消耗情况与具体细节。可以看到主要时间也是花费在Sending data步骤。其他步骤基本没有耗费太多时间。
SHOW PROFILES;
SHOW PROFILE;3)查看该语句的执行计划。其中type一栏显示为ALL,仍然是属于全表扫描,对表中的所有数据扫描了一次。
EXPLAIN SELECT id,salary FROM empsalary WHERE substr(id,1,3)='999';4.多表连接查询
查询9900号员工的领导(即部门经理)是谁。需要通过员工部门表和部门经理表联合查询。
1)编写语句进行查询。
SELECT a.id,b.id FROM leader a JOIN empdepartment b ON a.department=b.department AND b.id=9900;2)显示时间消耗情况与具体细节。可以看到主要时间仍然是花费在Sending data步骤,即数据的收集和发送。但此时是两张表的查询,需要进一步地分析和判断。
SHOW PROFILES;
SHOW PROFILE;3)显示执行计划。通过type一栏看到,分别对两张表做了ALL全表扫描,但rows一栏显示,其中a表(即leader部门经理表)数据量10行左右,远小于b表(即empdepartment员工部门表)的一万行左右。后者应该是性能瓶颈。此处需要注意,执行计划是根据数据库统计信息做出判断。此处属于数据库统计的估计值,并非准确的真实数据量。
EXPLAIN SELECT a.id,b.id FROM leader a JOIN empdepartment b ON a.department=b.department AND b.id=9900;5.复杂的多表连接查询
查询每个部门经理的工资。其中部门经理信息记录在leader表中,而工资记录在empsalary表中,需要关联查询。
1)编写语句进行查询。
SELECT id,salary FROM empsalary a WHERE EXISTS (SELECT 1 FROM leader b where a.id=b.id);2)显示时间消耗情况与具体细节。时间消耗统计中,没有哪一项是比较突出的,但存在非常多的executing(执行)和Sending data(收集获取和发送数据)项目,一共显示了100行。
SHOW PROFILES;
SHOW PROFILE;3)显示执行计划。此时select_type一栏不再是之前的simple,说明不再是简单的表扫描操作,而是存在子查询等复杂的计划,其中a表(empsalary员工工资表)select_type为PRIMARY,表示这张表属于查询中的最外层的表,也就是先查询了b表(leader表),才进一步查询了a表。而leader表的select_type为DEPENDENT SUBQUERY,表示先将外层的表数据查询出来,再用查询到的结果,逐一进行子查询。结合上一步的时间统计来看,内外部表的驱动顺序影响了整体的性能和步骤,产生了很多次循环的查询。
EXPLAIN SELECT id,salary FROM empsalary a WHERE EXISTS (SELECT 1 FROM leader b where a.id=b.id);
学员评价