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.数据源已排序

转载于:https://www.cnblogs.com/gered/p/8676652.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
连接更新可以通过以下几种方式进行优化: 1. 确保索引的使用:在连接的列上创建索引,以加快连接操作的速度。索引可以帮助数据库快速定位匹配的行,减少查询时间。确保连接列上的索引是合适的,并且统计信息是最新的。 2. 使用合适的连接条件:确保连接条件是准确的和合适的,以避免产生不必要的结果集。使用能够正确匹配行的条件,避免使用模糊或不准确的条件。 3. 选择合适的连接类型:根据查询需求选择合适的连接类型,如INNER JOIN、LEFT JOIN等。不同的连接类型对查询性能有影响,需要根据具体情况选择最优的连接类型。 4. 调整查询顺序:根据大小和数据分布情况,调整多连接的顺序。将较小的放在连接的后面,可以减少中间结果集的大小,提高查询性能。 5. 使用临时或子查询:将多连接拆分成多个步骤,使用临时或子查询来处理部分数据,以减少中间结果集的大小。这样可以降低内存和CPU的使用量,提高查询性能。 6. 避免全更新:如果只需要更新部分数据,可以使用更精确的条件来限制更新的行数。避免执行全更新操作,可以减少对的锁定时间和日志记录量。 7. 批量更新:将多个更新操作合并成一个批量更新,减少事务的提交次数。批量更新可以减少事务开销,提高更新性能。 8. 使用合适的数据库引擎:不同的数据库引擎对多连接更新的性能有差异。根据具体需求选择合适的数据库引擎,如InnoDB、MyISAM等。 以上是一些常见的优化方法,具体应该根据实际情况进行调整和优化。在进行优化之前,可以通过分析执行计划、使用性能分析工具等方式来了解查询的瓶颈所在,然后有针对性地进行优化。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值