在Teradata中,从执行计划来看:
1> in 和 exists的执行计划是一样的;
2> exists/not exists执行计划的唯一区别是join类型:Inclusion vs. exclusion;
3> in/not in :用in/not in时要非常注意是否有空值存在,因为teradata中任何值与null做任何操作所得到的结构都是unknown,因此优化器需要考虑空值比较的第三种逻辑值(unknown),如果连接字段可为空,将产生完全不同的执行计划。
从我的角度来说:
1> in的方式比较直观,exists则有些绕,而且in可以用于各种子查询,而exists好像只用于关联子查询(其他子查询当然也可以用,可惜没意义);
2> 在不能确保字段非空的情况下,建议使用exists/not exists,而不只用in/not in;
3> 实际测试两个时间长短并不稳定(各有长短),因此不能在实际操作之前确切说出哪个是最好的,只能通过查看执行计划来确定;
4> 我们也可以利用Left Outer Join来完成not in的操作,并且有时这么做可以获得更好的效率,这个也只能通过查看具体的执行计划来确定了。
题外话: 另外,teradata从性能上考虑,not in要比minus(all)要快很多,所以建议如果发现要比较大运算集合中每个字段都是非空(not null),则使用not in;如果不确定是否都是非空,则建议先做非空处理后再使用not in。
在oracle中,in/exists有比较大的效率差异:
1> select * from a1 where a in (select b from a2)
应该可以理解为select * from a1,(select b from a2) where a1.a= a2.b
从sql优化经验来看,a2应该不能是个大表,因为需要对a2进行全表的“唯一排序”,如果a2很大这个排序的性能就会很差,但是a1可以很大,因为a1.a=a2.b可以走索引。但如果a1.a和a2.b都有索引,那么a1和a2之间最佳的方案是走merge join。另外,如果a2.b上有索引,对a2的排序性能也有很大提高。
2> select * from a1 where exists ( select null from a2 where a = b )
一般都可以理解为是一个loop循环,由a1表的大小来决定loop循环的次数。如果想要此类sql效率高,那么循环次数就越少越优,因此exists应该是比较试用a1表比较小,a2表可以比较大的查询。
not in 和not exists:如果查询语句使用了not in 那么内外表都进行全表扫描,没有用到索引;而not extsts 的子查询依然能用到表上的索引。所以无论那个表大,用not exists都比not in要快。
因此,在oracle中有一条比较通用的规则
1> in适合于外表大而内表小的情况;exists适合于外表小而内表大的情况
2> 如果两个表相当则in/exists差别不大
3> 用not exists比not in执行的效率要高的多
4> 使用in时不对null进行处理
另外,我理解的是oracle中exists可能会比in的效率会好,因为:
1> exists检查是否有结果,判断是否有记录,返回的是一个布尔型(TRUE/FALSE),in是对结果值进行比较,判断一个字段是否存在于几个值的范围中。
2> exists主要用于片面的,有满足一个条件的即可,in主要用于具体的集合操作,有多少满足条件。
3> exists是判断是否存在这样的记录,in是判断某个字段是否在指定的某个范围内。
当然,可以实际测试一下的。
[@more@]