zoukankan      html  css  js  c++  java
  • MySQL阅读笔记——10.基于规则优化

    MySQL优化器会依据一些规则在执行前将语句进行优化,这个过程叫 语句重写

    • 移除不必要的括号

    • 某列和能够确定值的变量比较,直接替换为常量

    • 移除永真式和永假式

    • 计算常量表达式,索引列最好单独出现在表达式

    • 如果没有聚集函数以及分组条件,查询优化器会将HAVING和WHERE子句合并

    • 表中只有一条记录or没有记录or使用主键或者唯一二级索引等值连接查询的表称为 常量表 ,连接查询时会先查询 常量表 替换查询条件再查询其它表

    • 内连接 驱动表被驱动表 位置可以互换,不符合where条件的记录不参与连接,如果在where语句中将空值过滤则可以将外连接转换为内连接,从而进行优化

    10.1 子查询优化(主要针对IN子句优化)

      子查询必须用小括号括起来,放在from语句后面的子查询结果集叫做 派生表,只返回单一值的查询结果叫做 标量子查询(可以通过limit 1限制记录数,并指定返回某一列),子查询不依赖外层查询称为 不相关子查询,子查询依赖外层子查询称为 相关子查询

    不相关子查询:

      不相关的标量子查询或者行子查询,会单独执行子查询和外层查询,相当于两个单表连接查询,如果子查询是在IN子句则会先执行IN中子查询,再将结果集当作参数执行外层子查询

      对于不相关的IN查询,如果参数特别多则不能使用index dive,可能无法使用索引,只能对外层查询全表扫描,匹配时间也会很长。因此MySQL对子查询先尝试 半查询(semi-join),如果不能转换为 半查询 尝试 物化 之后再查询或者之间转换为 EXISTS语句再查询。

    • 半查询:等值查询不关心多少条记录于外层查询匹配,只关心是否存在与子查询匹配的记录,semi-join只是内部执行子查询的一种方式,具体由很多种方法:

      • 子查询中表上拉(Table pullout):子查询结果只有 主键或唯一索引 时候,可以指接把子查询上拉到FRPM语句后转换为内连接

      • 重复值消除(DuplicateWeedout execution strategy):转换为半连接查询,外围查询某条记录可能在子查询中对应多条记录,可以建立只有主键的临时表,每次匹配就将主键添加到该表,如果添加失败说明之前匹配过,则直接丢弃

      • 松散扫描(LooseScan execution strategy):如果子查询条件和返回列值相同,那么相同的列值只取一条去与外层查询匹配

      • 首次匹配(FirstMatch execution strategy):逐条读取外层记录,然后到子查询寻找匹配的记录

    • 因此MySQL将子查询结果放到基于内存的使用Memory引擎的临时表,并且建立哈希索引,如果子查询结构集非常大,超过系统变量tmp_table_sizemax_heap_table_size则会使用基于磁盘的存储引擎存放子查询结果,索引类型也转换为B+树,将子查询保存到临时表的过程叫做 物化,存储子查询结果集的临时表叫 物化表 之后将子查询转换为 内连接查询 选择最优执行方案

    由于相关子查询不是一个独立查询,不能在分析外围查询之前就 物化 子查询。 如果IN子查询不满足转换为semi-join的条件,又不能转换为物化表或者转换为物化表的成本太大,那么它就会被转换为EXISTS查询。

    • 转换为EXISTS查询:EXISTS语句范围truefalse,但是IN子句中有NULL则返回NULL,而一般in子句放在where或者on子句中,而where或者on子句不区分NULLFALSE

    用文字总结一下,只有符合下边这些条件的子查询才可以被转换为semi-join

    • 该子查询必须是和IN语句组成的布尔表达式,并且在外层查询的WHERE或者ON子句中出现。

    • 外层查询也可以有其他的搜索条件,只不过和IN子查询的搜索条件必须使用AND连接起来。

    • 该子查询必须是一个单一的查询,不能是由若干查询由UNION连接起来的形式。

    • 该子查询不能包含GROUP BY或者HAVING语句或者聚集函数。

    相关子查询:

    如果相关子查询再IN子句,意味着子查询依赖外查询的值,因此逐条从外查询取出记录然后去匹配执行内查询,相关子查询转换为EXIST语句后可能用到索引,提升效率

    # 相关子查询
    select * from s1 where key1 in (select key3 from s2 where s1.common_field = s2.common_field)
    # 转换为 EXISTS语句
    select * from s1 where exists (select 1 from s2 where s1.common_field = s2.common_field and s1.key1=s2.key3)

    子查询 放到外层查询的from后面,那么子查询的结果相当于一个 派生表,派生表有两种执行策略:首先尝试 和外层查询合并 ,如果不行,则会将 派生表物化 再进行查询


  • 相关阅读:
    cf B. Sereja and Suffixes
    cf E. Dima and Magic Guitar
    cf D. Dima and Trap Graph
    cf C. Dima and Salad
    最短路径问题(floyd)
    Drainage Ditches(网络流(EK算法))
    图结构练习—BFSDFS—判断可达性(BFS)
    Sorting It All Out(拓扑排序)
    Power Network(最大流(EK算法))
    Labeling Balls(拓扑)
  • 原文地址:https://www.cnblogs.com/leon618/p/13783320.html
Copyright © 2011-2022 走看看