zoukankan      html  css  js  c++  java
  • sql优化 表连接join方式

     
     
    sql优化核心 是数据库中 解析器+优化器的工作,我觉得主要有以下几个大方面:
    1>扫表的方法(索引非索引、主键非主键、书签查、索引下推)
    2>关联表的方法(三种),关键是内存如何利用
    3>处理排序聚合的方法,如何利用内存

    即 少扫磁盘多用内存

    --=====2 表关联方式
    -----0 概述
    类别 Nested Loop Hash Join Merge Join
    使用条件 任何条件 等值连接(=) 等值或非等值连接(>,<,=,>=,<=),‘<>’除外
    相关资源 CPU、磁盘I/O 内存、临时空间 内存、临时空间

    Nested Loop 优点: 当有高选择性索引或进行限制性搜索时效率比较高,能够快速返回第一次的搜索结果。
    缺点: 当索引丢失或查询条件限制不够时,效率低;当表纪录数多时,效率低
    实现: 从一张表中读取数据,访问另一张表(通常是索引)来做匹配,nested loops适用的场合是当一个关联表比较小的时候,效率会更高

    Hash Join 优点: 当无索引或索引条件模糊时,Hash Join比Nested Loop有效。通常比Merge Join快。在数据仓库环境下,如果表的纪录数多,效率高
    缺点: 为建立哈希表,需要大量内存。第一次的结果返回较慢
    实现: 将一个表(通常是小一点的那个表)做hash运算,将列数据存储到hash列表中,从另一个表中抽取记录,做hash运算,到hash 列表中找到相应的值,做匹配。

    Merge Join 优点: 当无索引或索引条件模糊时,Merge Join比Nested Loop有效。非等值连接时,Merge Join比Hash Join更有效
    缺点: 所有的表都需要排序。它为最优化的吞吐量而设计,并且在结果没有全部找到前不返回数据
    实现: 先将关联表的关联列各自做排序,然后从各自的排序表中抽取数据,到另一个排序表中做匹配,因为merge join需要做更多的排序,所以消耗的资源更多
    通常来讲,能够使用merge join的地方,hash join都可以发挥更好的性能



    选择什么连接类型有以下三要素:
    1) 表大小
    2) 连接列是否有索引
    3) 连接列是否要排序
    不同DBMS对表连接的支持:
    1) SqlServer, Oracle支持以下三种连接
    2) Mysql5.5前支持NestedLoop,之后支持对其的优化算法Block Nested-Loop

    -----1 Nested Loop Join
    驱动表(outer table),另一个为inner table,驱动表中的每一行与inner表中的相应记录JOIN。类似一个嵌套的循环。适用于驱动表的记录集比较小(<10000)且inner表的连接列上要有Index。
    注意:驱动表的记录集一定要小,inner表的连接列要有(UniqueIndex更好)索引。处理过程伪代码:
    for oi in count(outer table 行数):do
    for ii in count(inner table 行数):do --若inner连接列有主键索引,则不用循环inner表,也不需要回表,效率超高
    if oi.column=ii.column:do --若只是普通索引,还需要回表查相应数据(可能需要大量的随机IO),可能会慢许多,但也比没索引强
    Send To Client
    fi
    done
    done


    --Block Nested-Loop Join(仅Mysql支持)
    因为普通Nested-Loop一次只将一行传入内层循环, 所以outer table (的结果集)有多少行, 内存循环便要执行多少次.
    在inner table的连接上有索引的情况下,其扫描成本为O(Rn),若没有索引,则扫描成本为O(Rn*Sn)。如果inner table有很多记录,则Nested-Loops Join会扫描内部表很多次,执行效率会非常差。

    BNL算法:将outer table结果集存入join buffer, 内层循环的每一行与整个Join buffer中的记录做比较,从而减少内层循环的次数。
    举例,outer table结果集是100行,使用NLJ 需扫描内部表100次,如使用BNL,先把Outer Loop表每次读取的10行记录放到join buffer,然后在InnerLoop表中直接匹配这10行数据,
    内存循环就可以一次与这10行进行比较, 这样只需要比较10次,对内部表的扫描减少了9/10。所以BNL算法就能够显著减少内层循环表扫描的次数.

    MySQL使用Join Buffer有以下要点:
    当MySQL的 Join 有使用到 Block Nested-Loop Join,那么调大变量join_buffer_size 才是有意义的。而前面的 Index Nested-Loop Join如果仅使用索引进行Join,那么调大这个变量则毫无意义
    a) 只有在join类型为all, index, range的时候才可以使用join buffer。
    b) 能够被buffer的每一个join都会分配一个buffer, 也就是说一个query最终可能会使用多个join buffer。
    c) 第一个nonconst table不会分配join buffer, 即便其扫描类型是all或者index。
    d) 在join之前就会分配join buffer, 在query执行完毕即释放。
    e) join buffer中只会保存参与join的列, 并非整个数据行。
    f) 5.6版本及以后,优化器管理参数optimizer_switch中的block_nested_loop控制着BNL是否被用于优化器。默认条件下是开启,若果设置为off,优化器在选择 join方式的时候会选择NLJ算法。

    -----2 Hash Join
    将两表中较小的在内存中构造一个HASH表(只对连接列),扫描另一个表,同样对JOIN KEY进行HASH后探测是否可以JOIN。适用于记录集比较大的情况。
    需要注意的是:如果HASH表太大,无法一次构造在内存中,则分成若干个partition,写入磁盘的temporary segment,则会多一个写的代价,会降低效率



    -----3 Sort Merge Join
    通常情况下Hash Join的效果都比排序合并连接要好,然而如果行源已经被排过序,在执行排序合并连接时不需要再排序了,这时排序合并连接的性能会优于散列连接。
    可以使用USE_MERGE(table_name1 table_name2)来强制使用排序合并连接.
    Sort Merge join 用在没有索引,并且数据已经排序的情况.

    将两个表排序,然后将两个表合并。通常情况下,只有在以下情况发生时,才会使用此种JOIN方式:
    1.RBO模式 且 HASH_JOIN_ENABLED=false
    2.不等价关联(>,<,>=,<=,<>)
    3.数据源已排序
  • 相关阅读:
    .NET 统一用户管理 -- 统一鉴权
    .NET 统一用户管理 -- 单点登录
    基于.net 职责链来实现 插件模式
    电商开放平台设计
    docker搭建一个渗透测试环境 bwapp为例
    dcoker运行msf
    关于构造靶场
    判断网站是不是真实ip
    H3C设备配置ARP攻击防御
    Java代码审计 HTTP头操纵 response.addHeader()
  • 原文地址:https://www.cnblogs.com/gered/p/8676652.html
Copyright © 2011-2022 走看看