表连接和索引总结

 

 

nest loops

hash join

sort merge join

原理

先返回第一个表的结果集,然后依次循环地用第一个表的结果集中的一条结果,去匹配第二个表中的数据。因此,第一个表取出多少条数据,第二个表就会被访问多少次

先分别在两个表先hash运算后,缓存起来,使这些数据相对有序(但本身不排序),然后再通过比较相同的hash值整体进行表连接,所以每一个表最多将被访问一次。

先分别在两个表排序,然后再整体进行表连接,所以每一个表最多将被访问一次。sort merge join不分驱动表和被驱动表。

连接方式

支持各种连接(百搭

hash join绝大多数情况用于等值连接,不支持不等值连接。

绝大多数情况用于等值连接,只支持><这样的不等值连接,不支持其他的不等值连接

适用条件

1  驱动行源数据量小(不一定)。

2, 被驱动表关联的列上有索引,建索引的列上重复率低(不一定)。

 

做等值连接,而且连接列没索引(不一定)。

1两个表返回的结果集都不太大(不一定)。

2两个结果集基本有序(排序的代价相对较小)(不一定)

索引优化

发现有nested loops后,在where 语句的限制条件列上建索引,如果建完索引后,你发现还是nested loops,就在做连接的另一张表的连接字段建索引

发现hash loops后,最好在驱动表的限制条件上建索引,如果建完索引后还是hash join,此时在另一张表的连接条件上建索引效果不明显。

可以不建连接条件的索引。

发现sort merge join后,最好在驱动表的连接条件上建索引,建好索引后,执行代价会降低,如果此时还是sort merge join的话,而另一张表数据也很多,可以考虑在另一张表的连接条件上也建立索引。

可以建连接条件双方表的索引。

相关参数

 

hash loops的优化还可以考虑增大hash_area_size的值,或者简单调整pga的大小,尽量在内存中完成hash动作。

sort merge loops还可以考虑增大sort_area_size的值,或简单调整pga的大小,尽量在内存完成排序。

SELECT

select部分的字段越少效率越高,如果业务允许,查询字段就少一些。

1如果走了索引但出现了Table Access by ROWID(查询字段过多,只能通过rowid访问表的数据,称为索引回表)如果业务允许,可以减少select部分的字段为索引列,从而将执行计划改成index range scan(不访问表),达到优化的目的。

2如果业务必须要求某两三列必须出现,而索引只有一列,可以建复合索引,但是注意前导列必须是该条件,而且字段不能超过3个(最好2个)。实在要求很多字段必须出现,就保留索引回表,反正也算走索引了。

驱动表

1最右最上原则,先看缩进最右的行,同缩进的按照从上往下的顺序执行。先执行的就是驱动表(外部表),后执行的表就是被驱动表(内部表)。

2如果表连接的两列都没有索引或都有索引,连接时把返回较少行的表作为驱动表较好(nest loopshash join最明显,merge join也略有提升)

3不论表连接的方式如何,在被驱动表上列添加索引可以不同程度的减少表连接的代价(不论是不是大小表)

自然状态

1没hint自然情况下,优化器选择的执行计划一般是hash join。

2如果只有一个表A有索引,另一表B无索引无索引的表B通常作为驱动表,A表作为被驱动表。

F

ROm

1 RBO以从右到左的顺序处理表连接,也就是from 子句最右端table作为驱动表

2CBO无所谓。最好养成好的习惯,写from时把小表放后,大表放前。

WHERE

如果有多个条件,则按照从右向左顺序执行——A and 条件B and条件 C执行顺序是CBA,所以把最能筛选数据的列往后方,最好加索引。

聚合函数

1 如果有表中有非空约束列(not null)而且上面有索引,count,avg,sum这些聚合函数不管是写*还是写该非空列都可以走索引扫描,代价远小于全表扫描(扫索引块代价小).如果没有not null约束列,但是该列值没有非空的,而且上面有索引,写sql时添加该列is not null条件效果同上(推荐前一种)。

2 如果有表中有非空约束列(not null)而且上面有索引,或者没有not null约束列,但是该列值没有非空的,而且上面有索引,minmax都可以走索引扫描,代价远小于全表扫描(扫索引块的两端就行)。但是min max同时写更好的写法是select (select min(name) from A) max_val,(select max(name) from A) max_val from dual;

索引全扫描

index fast full scan(索引快速扫描和的)和index full scan(索引全扫描)的区别在于:索引快速扫描一次读多个索引块,速度更快,但是无法保证顺序,所以消除不了排序操作(比如不需要排序的count sum avg操作的例子);index full scan一次 读一个索引块,可以保证顺序,可以消除排序操作,减少了逻辑读(比如min max操作的例子)。

 

排序

注意如果是避免不了的order by语句,优化时可以考虑在该列建索引,可以极大地减少排序,因为索引是有序的。

主外键

如果是主外键约束,可以考虑在外键列加索引,可以提高连接效率(原理和nested loops相同),而且可以避免锁的竞争。

复合索引

一个列上可以同时存在单个索引和复合索引,但重点是前导性和选择性(要把最常出现和最能筛选数据的列放在最前面,前导列出现才走复合索引),复合索引的列不要超过3。复合索引的其他内容参看上面的SELECT部分。

位图索引

位图索引虽然省空间,对于count(*)效果好,但是致命弱点是怕dml操作,不适合oltp系统。比如男女(或0或1标志位)这样的字段,我们在oltp系统中宁愿不加索引也不用位图索引,因为它dml的加锁特性即使不影响update,也会影响Insert。

最重要

在生产库上大白天建索引而且还parallel 5——oltp不要轻易在白天有业务的时候建索引会死人的有木有,parallel虽然快但是会消耗大量资源有木有,生产库建索引要加online,否则锁整张表不能交易有木有。

 

猜你喜欢

转载自blog.csdn.net/qq_37440335/article/details/81061096