sql优化2
2022-03-28 本文已影响0人
chrisghb
一条查询sql语句的执行流程:
1.FROM <表名>
选取表,将<left_table>及<right_table>表数据通过笛卡尔积生成虚表VT1(此时VT1包括表中所有的字段?),
- ON <筛选条件>
对笛卡尔积的虚表VT1根据条件进行筛选VT2 - JOIN <join, left join, right join...> <join表>
指定join,保留表中未匹配的行就会作为外部行添加到虚拟表VT2中,产生虚表VT3,例如left join会将左表的剩余数据添加到虚表VT2中,生成虚表VT3
(FROM子句包含两个以上表,则对前面两个表生成的结果表VT3和下一个表重复依次执行3个步骤,直到处理完所有的表为止,这个是为什么?本质上,是因为笛卡尔是两个集合之间的操作) - WHERE <where条件>
对上述虚表VT3进行筛选, 将符合<where-condition>的记录才会被插入到虚表VT4(此时还没有进行group by,因此WHERE中出现对统计的过滤是不对的(不可以使得聚合函数),若需要则在having中实现。请思考一下,对于同样的筛选条件:在on和where 处进行筛选有结果会有不同?) - GROUP BY <分组条件>
分组, 根据分组条件,对VT4进行分组操作,生成虚表VT5(若是有group by,那么后面的所有步骤都只能得到的VT4的列及聚合函数(count、sum、avg等),即VT5虚表只会生成这些) - HAVING <分组筛选>
对分组后的结果进行筛选,即对虚表VT5进行筛选生成VT6 - SELECT<返回数据列表>
选择指定的列,生成虚拟表VT7(再次提醒:若有group by子句中,则此处除了group by子句中的列+聚合函数除外,不能再出现其它的列。请思考下,为什么不建议Select *from?) - DISTINCT
数据除重,生成VT8 - ORDER BY<排序条件>
将虚表VT8按照<order_by_list>进行排序操作,产生虚拟表VT9,请注意:这是唯一的一个可以使用select列表中别名的步骤? - LIMIT <行数限制>
取出指定行的记录,产生虚拟表VT10, 并将结果返回
最后:
实际上上述过程并不是绝对的,mysql优化器对部分过程进行优化以达到最佳的效果。
比如在select筛选出找到的数据集?
扩展:带有子查询的执行顺序
1. 不相关子查询:子查询的查询条件不依赖于父查询(由里向外 逐层处理。即每个子查询在上一级查询处理之前求解,子查询的结果用于建立其父查询的查找条件)
select * from emp where sal = (select max(sal) from emp);
先执行内层查询,作为where 条件再执行外层查询
2. 相关子查询:子查询的查询条件依赖于父查询(先取外层查询中表的第一个元组,根据它与内层查询相关的属性值处理内层查询,若WHERE子句返回值为真,则取此元组放入结果表,然后再取外层表的下一个元组,重复这一过程,直至外层表全部检查完为止)
select * from dept d where exists(select * from emp e where e.deptno = d.deptno);
先执行外层查询,再执行内层查询
对于笛卡尔积,有一个显而易见的SQL优化的方案是,当两张表的数据量比较大,又需要连接查询时,
应该使用 FROM table1 JOIN table2 ON xxx的语法,避免使用 FROM table1,table2 WHERE xxx 的语法。
因为后者会在内存中先生成一张数据量比较大的笛卡尔积表,增加了内存的开销。