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
引自:http://chenwenchaopy.blog.163.com/blog/static/1434909352011219101250116/
http://www.cnblogs.com/leoo2sk/archive/2011/08/11/consistent-hashing-intro.html
说到圆角显示,可能很多人的第一反应就是覆盖onDraw方法来自己画个圆角,可能以前写过其它Windows程序,比如Delphi的人会更有这种冲动吧。
不过在Android中,我们不需要这么麻烦,事实上整个Android系统的UI都是基于Style来实现的,有兴趣的朋友可以去研究一下Android的源码,看看如Button, Radio是如何实现的,就会明白Android的UI体系是非常强大、简单,又有趣的。
本文会以List View为例来讲解,如何使用Style来实现圆角(想想哪个控件已经是有圆角的了?)。
Android系统中的UI都是基于一个个的Style来显示的,同1个控件,换1个Style,效果就完全不同了。Style其实就是一堆显示属性的集合,包括文字属性,颜色设置,背景设置,而一堆Style的集合就构成了Theme.
尤其值得一提的是Style定义中经常会看到Selector,用于描述1个控件在不同的场景(Normal, Pressed, Disabled)下的显示。如以下的style定义代码:
文件:drawable/setting_button.xml
1 2 3 4 5 6
<?xml version="1.0" encoding="utf-8"?> <selector xmlns:android="http://schemas.android.com/apk/res/android"> <item android:state_pressed="true" android:drawable="@drawable/setting_icon_pressed"/> <item android:state_focused="true" android:drawable="@drawable/setting_icon_pressed"/> <item android:drawable="@drawable/setting_icon_normal"/> </selector>
这是最简单的selector定义,它的含义是有1个按钮,在pressed或focused时,显示图标@drawable/setting_icon_pressed,否则显示@drawable/setting_icon_normal,而这个selector本身就可以用在button的android:background属性中,如:android:background=”@drawable/setting_button”。如此一来,Android就会在你按下按钮的时候自动切换背景图片。
何为9-Patch讲到了背景图片,就必然会联想到图片的大小和缩放问题,总不能不断去麻烦美工MM来帮你修改图的大小吧,更何况我们还要适应Android手机众多的分辨率?
这就要说到9-Patch了,先来看看Google官方关于这个工具的1个截图:
首先,这是1个PNG图片。其次,在用draw9patch打开的时候,会自动在边缘添加1个像素点的透明边框。而这个边框就是你的工作范围了,左键点击会添加1个黑点,右键点击会去掉1个黑点,这些黑点连成的线就构成了9-Patch图片的效果。其中:左边和上面表述的是图片缩放的范围,右边和下边表述的是内容的Padding范围。
OK,我们来准备今天这个教程所需要的图片,请美工MM帮你画1个圆角图片吧,但不用切开,图片大小大概在40×40即可,主要是根据你所需要的最小的大小来决定,然后拖到draw9patch中,看下开始的效果。
然后我们在图片边缘点击进行绘制,并且点选下方2个Checkbox,结束时的效果如下图:
在使用这个图片时,左右2个绿色区域是会自动的上下拉伸,而上下2个绿色区域会自动的左右拉伸,中间的粉色区域会做4个方向的拉伸,至于4个角嘛,你已经知道了,它们不会缩放。而下方的的黑线表示,控件的内容会从最左边到最右边,几乎不留空隙,右边的黑线表示,控件的内容会在上下各留一些空间。
好了,将这个文件保存为float_panel.9.png,并保存到res/drawable目录下。记得扩展名必须是9.png,否则不会生效。另外下次你再次编辑这个文件时,draw9patch工具就不会再添加黑边了。
文件:res/layout/coner_round_list_activity.xml
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="fill_parent" android:layout_height="fill_parent" android:orientation="vertical" > <TextView android:text="Coner Round List View Sample" android:layout_width="fill_parent" android:layout_height="wrap_content" /> <ListView android:id="@+id/conerRoundListView" android:layout_width="fill_parent" android:layout_height="wrap_content" android:paddingTop="10dp" android:paddingBottom="10dp" android:layout_margin="10dp" android:background="@drawable/float_panel" android:layout_weight="1" android:cacheColorHint="#FFEDEDED" android:divider="#00EDEDED" /> </LinearLayout>
略做讲解:layout_margin是为了留点空间,更容易看出效果,backgroud就是用来设置9patch图片的。cacheColorHint的颜色与我所选用的背景图的颜色一样,可以确保滚动时的item底色不会变化。android:divider是用来控制分隔线的,这里我们不需要它,否则效果会受影响。(试试去掉这个属性?)
编写Activity类好了,我们写个类来使用这个布局文件吧,老规矩,从API DEMO中COPY了一个很长的String[]定义,并且使用ArrayAdapter来显示数据
1 2 3 4 5 6 7 8 9 10 11 12 13 14
public class ConerRoundListActivity extends Activity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.coner_round_list_activity); ListView arrowList=(ListView) findViewById(R.id.conerRoundListView); arrowList.setAdapter(new ArrayAdapter<String>(this, android.R.layout.simple_list_item_1, mStrings)); } private String[] mStrings = { "Abbaye de Belloc", "Abbaye du Mont des Cats", "Abertam", "Abondance", "Ackawi", ... }; }
平淡无奇的代码,这也是我为什么说在Android中设置圆角是一件很容易的事情。
最后,在运行程序之前,我们还要为这个activity进行一下额外的配置,打开manifest文件,修改或添加这个activity的定义如下:
1 2 3
<activity android:name=".conerround.ConerRoundListActivity" android:label="Coner Round List" android:theme="@android:style/Theme.Light" />
注意,我为这个activity指定了theme为android自带的Theme.Light,原因是这个theme的配色与我选的图片比较匹配(至少它的文字颜色是黑的,如果是默认Theme的白色,在背景图上的显示就看不清了)。
运行吧,最终的效果图如下:
总结Style, 9-Patch PNG, Background,这些元素混在一起,构成了Android在UI方面非常强大的功能,而且它还很简单,有兴趣的话可以读下源码,会对UI元素的使用有更深的了解,也许自己弄1个漂亮的Theme来供多个程序使用是一个不错的主意。
转自:http://www.learningandroid.net/blog/advance/9-patch-listview-coner/