34 | 到底可不可以使用join

34 | 到底可不可以使用join,第1张

1  join 有什么问题 ?

2  两个大小不同表 join, 哪个做驱动表?

主键索引 id 和 索引 a ,b 上无索引。 t2 插 1000 行, t1  100 行 。

select from t1  straight_join t2 on ( t1a=t2a );

straight_join 指定方式join :t1 驱动表,t2 被驱动表。

直接用 join , 优化器选驱动表 ,影响分析执行过程。

1  t1 读一行数据 R;       //全表扫描,扫描 100 行 ;

2  R 中a 字段到t2 里查    //树搜索,每次只扫一行, 总100 行 ;

3  t2 满足条件行+R = 结果集一部分(一行);

4  重复直到 t1 循环结束。

不使用 join, 单表 查询。不如直接 join 

1 select from t1,所有数据, 100 行 ; 1句

2从每一行 R 取出字段 a 的值 $Ra;select from t2 where a=$Ra; 100 行 ; 100 句

3返回结果+R = 结果集一行。// 多100 次交互: 拼接 SQL 语句和结果 。

驱动表(行数 N):全表扫描,被驱动表(行数M):树搜索。

树搜索复杂度: 2 为底M对数,log2M,查一行是 2log2M

驱动表: N 行到被驱动表上匹配一次。

近似复杂度N + N2log2M。

N 对扫描行数影响更大, 小表做驱动表。

select from t1  straight_join t2 on (t1a= t2b );

b 上没有索引, t2 全表扫描(100次)。总共扫描 1001000=10 万行。

t1 和 t2 都是 10 万行表,要扫描 100 亿行,太“笨重”,MySQL 没用这个算法

三、Block Nested-Loop Join 没可用索引

1   t1读入线程 内存 join_buffer 中 ,select 整个 t1 放内存;

2  扫描 t2,每行取出,跟 join_buffer 对比 ,满足 join 条件作为结果集一部分返回。

内存 *** 作,速度快多,性能好 。时间复杂度和上面一样

都一样

1  总扫描行 M+N;(1100)

2  判断次数是 MN。(1001000=10 万次join_buffer 无序数组)

分段放 (Block由来) 。join_buffer_size 默认 256k, 改成 1200,再执行:

1  扫描表 t1,顺序读取数据行放入 join_buffer 中, 放完第 88 行 join_buffer 满

2 扫描表 t2,把 t2 中的每一行取出来,跟 join_buffer 中的数据做对比,满足 join 条件的,作为结果集的一部分返回;

3  清空 join_buffer;重复上面

判断等值条件的次数还是不变的,依然是(88+12)1000=10 万次。

小表 当驱动表。驱动表 N行,分 K段完成,被驱动表M行。

K = λN,λ (0,1),N 越大 K 越大

1  扫描行数N+λNM;

2  内存判断 NM 次。

考虑扫描行数,N 小结果小。λ才是关键因素,越小越好。

N 固定,什么参数会影响 K 的大小呢?(就是λ的大小)join_buffer_size。 分段越少,扫描次数越少。

join 语句很慢,把 join_buffer_size 改大 。

1   Index Nested-Loop Join 算法,没问题;

2  Block Nested-Loop Join 算法 不要 ,扫描行多。尤其大表上 join *** 作,扫描被驱动表很多次,会占用大量的系统资源。

explain 结果,Extra 有没有出现“Block Nested Loop”字样。

1  Index Nested-Loop Join , 小表

2  Block Nested-Loop Join 算法:

join_buffer_size 足够 大 , 一样 ; 不够 , 小表

select from t1  straight_join t2 on (t1b=t2b) where t2id<=50;

select from t2   straight_join t1 on (t1b=t2b) where t2id<=50;

都用不上索引, 第二 :join_buffer 只放t2 前 50 行 ( 是“小表” ), 更好

另一组例子:

select t1b,t2  from  t1  straight_join t2 on (t1b=t2b) where  t2id<=100;

select t1b,t2  from  t2  straight_join t1 on (t1b=t2b) where  t2id<=100;

t1 放到 join_buffer 中,只放b值 (小表) t1 为驱动表。

 t2 放 id、a 和 b。

两个表按照各自条件过滤,计算参与 join 各个字段总数据量,数据量小就是 “ 小表 ” ,驱动表。

能否用 被驱动表索引 ,对 join 性能 影响大

用被 驱动表 索引 , join 好 ;否则,不要用;

用 join 时, 小表做驱动表

Block Nested-Loop Join 算法,可能会因为 join_buffer 不够大,被驱动表做多次全表扫描。

被驱动表 是 大表 (冷数据),除查询可能会IO 压力大,MySQL 服务还有什么更严重影响?(结合上一篇知识点)

两种情况:

(1) 数据量小于old ,驱动表分段,被驱动表 多次读 ,大表,循环读取间隔超1秒, 移到young区 。 Buffer pool hit rate 命中率极低,其他请求 读磁盘 , 响应慢,阻塞。

(2 )被驱动表数据量大于 Buffer Pool ,影响young部分更新

评论1

为什么会进入young区域?

大表t M页>old区域N页,对t进行k次全表扫描。第一次扫描时,1~N页依次被放入old区域,访问N+1页时淘汰1页,放入N+1页,以此类推,第一次扫描结束后old区域存放的是M-N+1~M页。第二次扫描开始,访问1页,淘汰M-N+1页,放入1页。可以把M页想象成一个环,N页想象成在这个环上滑动的窗口,由于M>N, 不管是哪次扫描,需要访问的页都不会在滑动窗口上,所以不会存在“被访问的时候数据页在 LRU 链表中存在的时间超过了 1 秒“而被放入young的情况。 我能想到的会被放入young区域的情况是,在当次扫描中,由于一页上有多行数据,需要对该页访问多次,超过了1s,不管这种情况就和t大小没关系了,而是由于page size太大,而一行数据太少。

 join_buffer 不够大,多次全表扫描,“ 长事务 ”。除了导致 undo log 不能被回收 , 回滚段空间膨胀 问题,还会出现:

1 长期 占DML锁 ,引发 DDL拿不到锁 , 堵满连接池 ;

 2 SQL执行 socket_timeout 超时后业务接口 重复发起 , IO负载上升 雪崩;

3 实例异常,DBA kill SQL因繁杂的回滚执行时间过长, 不能快速恢复 ;

4 select 返回, 网络拥堵,拖慢服务端 ;

数据库优化你学理论不如进行实践。其实这个公式偏向于SQL优化,进行排序性聚合算法

Br+BrBs/(K-1) 这个就是嵌套循环连接算法(join)的效率估算公式

sql:

select from table1 as R

inner join tabel2 as S on Rid=Sid

其中:

B=全表

r代表R为别名的表table1,s代表S为别名的表table2

Br和Bs就是代表 table1 和 table2了

K为内存缓冲区块,系统会分配K-1块给相关的表辨得出Br+BrBs/(K-1)

(FrsNrNs)/MrsNr 则是系统筛选算法估算,

N=元组总数,F=选择率,M=链接结果

Frs就是r和s的合并量

Nr和Ns就是table1和tabel2的总元素

Mrs则是符合条件Rid=Sid的链接结果因子块

Java的标准库里面没有类似这样的函数,不过你完全可以自己实现一个,提高效率就用StringBuffer实现

import javautilArrayList;

import javautilList;

public class StringBuilderDemo1 {

public static String join(String join,String[] strAry){

StringBuffer sb=new StringBuffer();

for(int i=0;i<strArylength;i++){

if(i==(strArylength-1)){

sbappend(strAry[i]);

}else{

sbappend(strAry[i])append(join);

}

}

return new String(sb);

}

public static void main(String[] args){

String[] sa={"a","b","c"};

String s1=StringBuilderDemo1join("-",sa);

Systemoutprintln(s1);

}

}

以上就是关于34 | 到底可不可以使用join全部的内容,包括:34 | 到底可不可以使用join、数据库排序合并算法中,cost=Br+Bs+(Frs*Nr*Ns)/Mrs.Nr和Ns是什么、java有没有类似leftjoin的算法等相关内容解答,如果想了解更多相关内容,可以关注我们,你们的支持是我们更新的动力!

欢迎分享,转载请注明来源:内存溢出

原文地址: http://outofmemory.cn/sjk/9757865.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2023-05-01
下一篇 2023-05-01

发表评论

登录后才能评论

评论列表(0条)

保存