Oracle,SQL语句中*+*是什么技术

Oracle,SQL语句中*+*是什么技术,第1张

运用的是oracle 中的哈希连接,/*+ */ 相当于代码中的编译指令,要求oracle按照指定的某种轨则执行,而不是使用默认设定use_hash(a,b)是其一一种 当内存能够提供足够的空间时,哈希(HASH)连接是Oracle优化器通常的选择。哈希连接中,优化器根据统计信息,首先选择两个表中的小表,在内存中建立这张表的基于连接键的哈希表优化器再扫描表连接中的大表,将大表中的数据与哈希表进行比较,如果有相关联的数据,则将数据添加到结果集中。  当表连接中的小表能够完全cache到可用内存的时候,哈希连接的效果最佳。哈希连接的成本只是两个表从硬盘读入到内存的成本。  但是,如果哈希表过大而不能全部cache到可用内存时,优化器将会把哈希表分成多个分区,再将分区逐一cache到内存中。当表的分区超过了可用内存时,分区的部分数据就会临时地写到磁盘上的临时表空间上。因此,分区的数据写磁盘时,比较大的区间(EXTENT)会提高I/O性能。ORACLE推荐的临时表空间的区间是1MB。临时表空间的区间大小由UNIFORM SIZE指定。  当哈希表构建完成后,进行下面的处理:  1) 第二个大表进行扫描  2) 如果大表不能完全cache到可用内存的时候,大表同样会分成很多分区  3) 大表的第一个分区cache到内存  4) 对大表第一个分区的数据进行扫描,并与哈希表进行比较,如果有匹配的纪录,添加到结果集里面  5) 与第一个分区一样,其它的分区也类似处理。  6) 所有的分区处理完后,ORACLE对产生的结果集进行归并,汇总,产生最终的结果。  当哈希表过大或可用内存有限,哈希表不能完全CACHE到内存。随着满足连接条件的结果集的增加,可用内存会随之下降,这时已经CACHE到内存的数据可能会重新写回到硬盘去。如果出现这种情况,系统的性能就会下降。  当连接的两个表是用等值连接并且表的数据量比较大时,优化器才可能采用哈希连接。哈希连接是基于CBO的。只有在数据库初始化参数HASH_JOIN_ENABLED设为True,并且为参数PGA_AGGREGATE_TARGET设置了一个足够大的值的时候,Oracle才会使用哈希边连接。HASH_AREA_SIZE是向下兼容的参数,但在Oracle9i之前的版本中应当使用 HASH_AREA_SIZE。当使用ORDERED提示时,FROM子句中的第一张表将用于建立哈希表。

in子查询、exists子查询、连接,效率的探讨

以下是SQL的帮助 (高级查询优化概念)

Microsoft® SQL Server™ 2000 使用内存中的排序和哈希联接技术执行排序、交集、联合、差分等 *** 作。SQL Server 利用这种类型的查询计划支持垂直表分区,有时称其为分列存储。

SQL Server 使用三种类型的联接 *** 作:

嵌套循环联接

合并联接

哈希联接

如果一个联接输入很小(比如不到 10 行),而另一个联接输入很大而且已在其联接列上创建索引,则索引嵌套循环是最快的联接 *** 作,因为它们需要最少的 I/O 和最少的比较。有关嵌套循环的更多信息,请参见了解嵌套循环联接。

如果两个联接输入并不小但已在二者联接列上排序(例如,如果它们是通过扫描已排序的索引获得的),则合并联接是最快的联接 *** 作。如果两个联接输入都很大,而且这两个输入的大小差不多,则预先排序的合并联接提供的性能与哈希联接相似。然而,如果两个输入的大小相差很大,则哈希联接 *** 作通常快得多。有关更多信息,请参见了解合并联接。

哈希联接可以有效处理很大的、未排序的非索引输入。它们对复杂查询的中间结果很有用,因为:

中间结果未经索引(除非已经显式保存到磁盘上然后创建索引),而且生成时通常不为查询计划中的下一个 *** 作进行适当的排序。

查询优化器只估计中间结果的大小。由于估计的值在复杂查询中可能有很大的误差,因此如果中间结果比预期的大得多,则处理中间结果的算法不仅必须有效而且必须适度弱化。

哈希联接使得对非规范化的使用减少。非规范化一般通过减少联接 *** 作获得更好的性能,尽管这样做有冗余之险(如不一致的更新)。哈希联接则减少使用非规范化的需要。哈希联接使垂直分区(用单独的文件或索引代表单个表中的几组列)得以成为物理数据库设计的可行选项。有关更多信息,请参见了解哈希联接。

Oracle中关于in和exists,not in 和 not exists

in和exists

in 是把外表和内表作hash 连接,而exists是对外表作loop循环,每次loop循环再对内表进行查询。

not exists:做NL,对子查询先查,有个虚表,有确定值,所以就算子查询有NULL最终也有值返回

not in:做hash,对子查询表建立内存数组,用外表匹配,那子查询要是有NULL那外表没的匹配最终无值返回。

一直以来认为exists比in效率高的说法是不准确的。

如果查询的两个表大小相当,那么用in和exists差别不大。

如果两个表中一个较小,一个是大表,则子查询表大的用exists,子查询表小的用in:

例如:表A(小表),表B(大表)

1:

select * from A where cc in (select cc from B)

效率低,用到了A表上cc列的索引;

select * from A where exists(select cc from B where cc=A.cc)

效率高,用到了B表上cc列的索引。

相反的

2:

select * from B where cc in (select cc from A)

效率高,用到了B表上cc列的索引;

select * from B where exists(select cc from A where cc=B.cc)

效率低,用到了A表上cc列的索引。

not in 和not exists

如果查询语句使用了not in 那么内外表都进行全表扫描,没有用到索引;

而not extsts 的子查询依然能用到表上的索引。

所以无论那个表大,用not exists都比not in要快。

一直听到的都是说尽量用exists不要用in,因为exists只判断存在而in需要对比值,所以exists比较快,但看了看网上的一些东西才发现根本不是这么回事。

下面这段是抄的

Select * from T1 where x in ( select y from T2 )

执行的过程相当于:

select *

from t1, ( select distinct y from t2 ) t2

where t1.x = t2.y

select * from t1 where exists ( select null from t2 where y = x )

执行的过程相当于:

for x in ( select * from t1 )

loop

if ( exists ( select null from t2 where y = x.x )

then

OUTPUT THE RECORD

end if

end loop

从我的角度来说,in的方式比较直观,exists则有些绕,而且in可以用于各种子查询,而exists好像只用于关联子查询(其他子查询当然也可以用,可惜没意义)。

由于exists是用loop的方式,所以,循环的次数对于exists影响最大,所以,外表要记录数少,内表就无所谓了,而in用的是hash join,所以内表如果小,整个查询的范围都会很小,如果内表很大,外表如果也很大就很慢了,这时候exists才真正的会快过in的方式。

not in 和not exists

如果查询语句使用了not in 那么内外表都进行全表扫描,没有用到索引;

而not extsts 的子查询依然能用到表上的索引。

所以无论那个表大,用not exists都比not in要快。

也就是说,in和exists需要具体情况具体分析,not in和not exists就不用分析了,尽量用not exists就好了。

典型的连接类型共有3种:

排序 - - 合并连接(Sort Merge Join (SMJ) )

嵌套循环(Nested Loops (NL) )

哈希连接(Hash Join)

嵌套循环和哈希连接的算法还是有不同,在理论上哈希连接要快过排序和nl,当然实际情况比理论上有复杂的多,不过两者还是有差异的.

1 关联子查询与非关联子查询

关联子查询需要在内部引用外部表,而非关联子查询不要引用外部表。对于父查询中处理的记录来说,一个关联子查询是每行计算一次,然而一个非关联子查询只会执行一次,而且结果集被保存在内存中(如果结果集比较小),或者放在一张oracle临时数据段中(如果结果集比较大)。一个“标量”子查询是一个非关联子查询,返回唯一记录。如果子查询仅仅返回一个记录,那么oracle优化器会将结果缩减为一个常量,而且这个子查询只会执行一次。

/*select * from emp where deptno in (select deptno from dept where dept_name='admin')*/

2.如何选择?

根据外部查询,以及子查询本身所返回的记录的数目。如果两种查询返回的结果是相同的,哪一个效率更好?

关联子查询的系统开销:对于返回到外层查询的记录来说,子查询会每次执行一次。因此,必须保证任何可能的时候子查询都要使用索引。

非关联子查询的系统开销:子查询只会执行一次,而且结果集通常是排好序的,并保存在临时数据段中,其中每一个记录在返回时都会被父级查询引用,在子查询返回大量记录的情况下,将这些结果集排序回增大系统的开销。

所以:如果父查询只返回较少的记录,那么再次执行子查询的开销不会非常大,如果返回很多数据行,那么直查询就会执行很多次。 如果子查询返回较少的记录,那么为内存中保存父查询的结果集的系统开销不会非常大,如果子查询返回多行,那么需要将结果放在临时段上,然后对数据段排序,以便为负查询中的每个记录服务。

3结论:1)在使用一个关联子查询是,使用in 或者 exists子句的子查询执行计划通常都相同

2)exists子句通常不适于子查询

3)在外部查询返回相对较少记录时,关联子查询比非关联子查询执行得要更快。

4)如果子查询中只有少量的记录,则非关联子查询会比关联子查询执行得更快。

4 子查询转化:子查询可以转化为标准连接 *** 作

1)使用in的非关联子查询(子查询唯一)

条件:1)在整个层次结构中最底层数据表上定义唯一主键的数据列存在于子查询的select列表中

2)至少有个定义了唯一主键的数据列在select列表中,而且定义唯一主键的其他数据列都必须有指定的相等标准,不管是直接指定,还是间接指定。

2)使用exists子句的关联子查询

条件:对于相关条件来说,该子查询只能返回一个记录。

5。not in和not exists调整

1)not in 非关联子查询:转化为in写法下的minus子句

2)not exists关联子查询:这种类型的反连接 *** 作会为外部查询中每一个记录进行内部查询,除了不满足子查询中where条件的内部数据表以外,他会过滤掉所有记录。

可以重写:在一个等值连接中指定外部链接条件,然后添加select distinct

eg:select distinct ... from a,b where a.col1 = b.col1(+) and b.col1 is null

6。在子查询中使用all any

1. 1. 简介

本文简要介绍了关联子查询、非关联子查询、IN &EXISTS 、 NOT IN &NOT EXISTS之间的区别;同时对不同数据库版本下CBO对IN &EXISTS &NOT IN &NOT EXISTS的处理做了一定的阐述。

2. os、数据库版本以及测试数据

os:windows 2000 server sp4

db:oracle 10.1.0.2

set time on

set timing on

drop table outer_large_t

/

create table outer_large_t

(id number,

c1 varchar2(100),

c2 varchar2(100)

)

/

create index idx_outer_large_t on outer_large_t(id)

/

drop table outer_small_t

/

create table outer_small_t

as select *from outer_large_t

where 1=2

/

create index idx_outer_small_t_id on outer_small_t(id)

/

drop table inner_large_t

/

create table inner_large_t

(id number,

c3 varchar2(100),

c4 varchar2(100)

)

/

create index idx_inner_large_t_1 on inner_large_t(id,c3)

/

drop table inner_small_t

/

create table inner_small_t

(id number,

c3 varchar2(100),

c4 varchar2(100)

)

/

create index idx_inner_small_t on inner_small_t(id,c3)

/

3. 2.关联子查询和非关联子查询

测试数据:

truncate table outer_large_t

/

truncate table inner_large_t

/

declare

begin

for i in 1..50000 loop

insert into outer_large_t values (i,'test','test')

end loop

for i in 30000..100000 loop

insert into inner_large_t values (i,'test','test')

end loop

commit

end

/

analyze table outer_large_t compute statistics for table for all indexes

/

analyze table inner_large_t compute statistics for table for all indexes

/

非关联子查询形如:

select count(*) from outer_large_t

where id not in

(select id from inner_large_t)

/

子查询与父查询没有关联。

关联子查询形如:

select count(*) from outer_large_t outer_t

where not exists

(select id from inner_large_t where id = outer_t.id)

/

子查询与父查询存在关联id = outer_t.id。

非关联子查询对于exists和not exists是没有意义的。

看如下实验:

11:17:00 test@GZSERVER>select count(*) from outer_large_t

11:17:02 2 where id not in

11:17:02 3 (select id from inner_large_t)

11:17:02 4 /

COUNT(*)

----------

29999

已用时间: 00: 00: 00.04

11:17:02 test@GZSERVER>select count(*) from outer_large_t

11:17:02 2 where id in

11:17:02 3 (select id from inner_large_t)

11:17:02 4 /

COUNT(*)

----------

20001

已用时间: 00: 00: 00.01

11:17:02 test@GZSERVER>select count(*) from outer_large_t outer_t

11:17:02 2 where not exists

11:17:02 3 (select id from inner_large_t)

11:17:02 4 /

COUNT(*)

----------

0

已用时间: 00: 00: 00.00

11:17:02 test@GZSERVER>select count(*) from outer_large_t outer_t

11:17:02 2 where exists

11:17:02 3 (select id from inner_large_t)

11:17:02 4 /

COUNT(*)

----------

50000

已用时间: 00: 00: 00.00

11:17:03 test@GZSERVER>

非关联子查询使用not exists的话父查询总是返回0,使用exists总是返回父查询的查询结果集。


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

原文地址:https://54852.com/sjk/6700817.html

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

发表评论

登录后才能评论

评论列表(0条)

    保存