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


  • 相关阅读:
    DevExpress_Winform_使用汇总
    SVN的可视化日志统计工具StatSVN
    jenkins搭建.Net项目自动构建
    关闭tab时,定位到导航栏对应的激活tab
    DevExpress.XtraNavBar.NavBarControl 模拟单击导航的选项事件
    选中Tab控件单击事件,点击tab头,定位到导航栏的选项,为选中状态 ,DevExpress.XtraNavBar.NavBarControl 导航控件定位或选中状态 另导航的选项为选中状态.
    WCF服务部署到IIS问题汇总
    iOS多线程编程
    最新版SDWebImage的使用
    前端入门系列之CSS
  • 原文地址:https://www.cnblogs.com/leon618/p/13783320.html
Copyright © 2011-2022 走看看