sql优化2

2022-03-28  本文已影响0人  chrisghb

一条查询sql语句的执行流程:
1.FROM <表名>
 选取表,将<left_table>及<right_table>表数据通过笛卡尔积生成虚表VT1(此时VT1包括表中所有的字段?),

  1. ON <筛选条件>
     对笛卡尔积的虚表VT1根据条件进行筛选VT2
  2. JOIN <join, left join, right join...> <join表>
     指定join,保留表中未匹配的行就会作为外部行添加到虚拟表VT2中,产生虚表VT3,例如left join会将左表的剩余数据添加到虚表VT2中,生成虚表VT3
    (FROM子句包含两个以上表,则对前面两个表生成的结果表VT3和下一个表重复依次执行3个步骤,直到处理完所有的表为止,这个是为什么?本质上,是因为笛卡尔是两个集合之间的操作)
  3. WHERE <where条件>
     对上述虚表VT3进行筛选, 将符合<where-condition>的记录才会被插入到虚表VT4(此时还没有进行group by,因此WHERE中出现对统计的过滤是不对的(不可以使得聚合函数),若需要则在having中实现。请思考一下,对于同样的筛选条件:在on和where 处进行筛选有结果会有不同?)
  4. GROUP BY <分组条件>
     分组, 根据分组条件,对VT4进行分组操作,生成虚表VT5(若是有group by,那么后面的所有步骤都只能得到的VT4的列及聚合函数(count、sum、avg等),即VT5虚表只会生成这些)
  5. HAVING <分组筛选>
     对分组后的结果进行筛选,即对虚表VT5进行筛选生成VT6
  6. SELECT<返回数据列表>
     选择指定的列,生成虚拟表VT7(再次提醒:若有group by子句中,则此处除了group by子句中的列+聚合函数除外,不能再出现其它的列。请思考下,为什么不建议Select *from?)
  7. DISTINCT
     数据除重,生成VT8
  8. ORDER BY<排序条件>
     将虚表VT8按照<order_by_list>进行排序操作,产生虚拟表VT9,请注意:这是唯一的一个可以使用select列表中别名的步骤?
  9. 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 的语法。
因为后者会在内存中先生成一张数据量比较大的笛卡尔积表,增加了内存的开销。

上一篇下一篇

猜你喜欢

热点阅读