#
网页打开的最佳速度
2秒!
许多研究都表明,用户最满意的打开网页时间,是在2秒以下。用户能够忍受的最长等待时间的中位数,在6~8秒之间。这就是说,8秒是一个临界值,如果你的网站打开速度在8秒以上,那么很可能,大部分访问者最终都会离你而去。
研究显示,如果等待12秒以后,网页还是没有载入,那么99%以上的用户会关闭这个网页,不再等待。
但是,如果在等待载入期间,网站能够向用户显示反馈消息,比如一个进度条,那么用户可以忍受的时间会延长到38秒。
对访问者的心理影响
根据一些抽样调查,访问者倾向于认为,打开速度较快的网站质量更高,更可信,也更有趣。
相对应地,网页打开速度越慢,访问者的心理挫折感就越强,就会对网站的可信性和质量产生怀疑。在这种情况下,用户会觉得网站的后台可能出现了一些错
误,因为在很长一段时间内,他没有得到任何提示。而且,缓慢的打开速度会让用户忘了下一步要干什么,不得不重新回忆,这会进一步恶化用户的使用体验。
这个指标对电子商务网站尤其重要。载入速度越快,就越容易使访问者变成你的客户,降低客户选择商品后、最后却放弃结账的比例。
不过,网站反应速度也不宜太快,否则用户会增加与服务器互动的频率,这可能加大出现错误的概率。
一些实证结果
Google做过一个试验,显示10条搜索结果的页面载入需要0.4秒,显示30条搜索结果的页面载入需要0.9秒,结果后者使得Google总的流量和收入减少了20%。
Google地图上线的时候,首页大小有100KB,后来下降到70~80KB。结果,流量在第一个星期上升了10%,接下来的3个星期又再上升了25%。
Amazon的统计也显示了相近的结果,首页打开时间每增加100毫秒,网站销售量会减少1%。
宽带与窄带的区别
有研究显示,宽带用户比窄带用户更没有耐心。宽带用户愿意忍受的最长等待时间,往往只有4~6秒。
网站制作者必须记住,在ADSL条件下,3~5秒就能载入的网页,在窄带条件下需要20~30秒才能打开。因此,网页总的大小——包括图片、Javascript和CSS文件的大小——不宜过大,这样对宽带和窄带用户都有利。
1. /*+ALL_ROWS*/
表明對語句塊選擇基於開銷的優化方法,並獲得最佳吞吐量,使資源消耗最小化.
例如:
SELECT /*+ALL_ROWS*/ EMP_NO,EMP_NAM,DAT_IN FROM BSEMPMS WHERE EMP_NO='SCOTT';
2./*+FIRST_ROWS*/
表明對語句塊選擇基於開銷的優化方法,並獲得最佳回應時間,使資源消耗最小化.
例如:
SELECT/*+FIRST_ROWS*/ EMP_NO,EMP_NAM,DAT_IN FROM BSEMPMS WHERE EMP_NO='SCOTT';
3./*+CHOOSE*/
表明如果資料字典中有訪問表的統計資訊,將基於開銷的優化方法,並獲得最佳的吞吐量;
表明如果資料字典中沒有訪問表的統計資訊,將基於規則開銷的優化方法;
例如:
SELECT/*+CHOOSE*/ EMP_NO,EMP_NAM,DAT_IN FROM BSEMPMS WHERE EMP_NO='SCOTT';
4./*+RULE*/
表明對語句塊選擇基於規則的優化方法.
例如:
SELECT/*+ RULE */ EMP_NO,EMP_NAM,DAT_IN FROM BSEMPMS WHERE EMP_NO='SCOTT';
5./*+FULL(TABLE)*/
表明對表選擇全局掃描的方法.
例如:
SELECT/*+FULL(A)*/ EMP_NO,EMP_NAM FROM BSEMPMS A WHERE EMP_NO='SCOTT';
6./*+ROWID(TABLE)*/
提示明確表明對指定表根據ROWID進行訪問.
例如:
SELECT/*+ROWID(BSEMPMS)*/ * FROM BSEMPMS WHERE ROWID>='AAAAAAAAAAAAAA' AND EMP_NO='SCOTT';
7./*+CLUSTER(TABLE)*/
提示明確表明對指定表選擇簇掃描的訪問方法,它只對簇物件有效.
例如:
SELECT/*+CLUSTER */ BSEMPMS.EMP_NO,DPT_NO FROM BSEMPMS,BSDPTMS
WHERE DPT_NO='TEC304' AND BSEMPMS.DPT_NO=BSDPTMS.DPT_NO;
8./*+INDEX(TABLE INDEX_NAME)*/
表明對表選擇索引的掃描方法.
例如:
SELECT/*+INDEX(BSEMPMS SEX_INDEX) USE SEX_INDEX BECAUSE THERE ARE FEWMALE BSEMPMS */ FROM BSEMPMS WHERE SEX='M';
9./*+INDEX_ASC(TABLE INDEX_NAME)*/
表明對表選擇索引昇冪的掃描方法.
例如:
SELECT/*+INDEX_ASC(BSEMPMS PK_BSEMPMS) */ FROM BSEMPMS WHERE DPT_NO='SCOTT';
10./*+INDEX_COMBINE*/
為指定表選擇點陣圖訪問路經,如果INDEX_COMBINE中沒有提供作為參數的索引,將選擇出點陣圖索引的布林組合方式.
例如:
SELECT/*+INDEX_COMBINE(BSEMPMS SAL_BMI HIREDATE_BMI)*/ * FROM BSEMPMS
WHERE SAL<5000000 AND HIREDATE<SYSDATE;
11./*+INDEX_JOIN(TABLE INDEX_NAME)*/
提示明確命令優化器使用索引作為訪問路徑.
例如:
SELECT/*+INDEX_JOIN(BSEMPMS SAL_HMI HIREDATE_BMI)*/ SAL,HIREDATE
FROM BSEMPMS WHERE SAL<60000;
12./*+INDEX_DESC(TABLE INDEX_NAME)*/
表明對表選擇索引降冪的掃描方法.
例如:
SELECT/*+INDEX_DESC(BSEMPMS PK_BSEMPMS) */ FROM BSEMPMS WHERE DPT_NO='SCOTT';
13./*+INDEX_FFS(TABLE INDEX_NAME)*/
對指定的表執行快速全索引掃描,而不是全表掃描的辦法.
例如:
SELECT/*+INDEX_FFS(BSEMPMS IN_EMPNAM)*/ * FROM BSEMPMS WHERE DPT_NO='TEC305';
14./*+ADD_EQUAL TABLE INDEX_NAM1,INDEX_NAM2,...*/
提示明確進行執行規劃的選擇,將幾個單列索引的掃描合起來.
例如:
SELECT/*+INDEX_FFS(BSEMPMS IN_DPTNO,IN_EMPNO,IN_SEX)*/ * FROM BSEMPMS WHERE EMP_NO='SCOTT' AND DPT_NO='TDC306';
15./*+USE_CONCAT*/
對查詢中的WHERE後面的OR條件進行轉換為UNION ALL的組合查詢.
例如:
SELECT/*+USE_CONCAT*/ * FROM BSEMPMS WHERE DPT_NO='TDC506' AND SEX='M';
16./*+NO_EXPAND*/
對於WHERE後面的OR 或者IN-LIST的查詢語句,NO_EXPAND將阻止其基於優化器對其進行擴展.
例如:
SELECT/*+NO_EXPAND*/ * FROM BSEMPMS WHERE DPT_NO='TDC506' AND SEX='M';
17./*+NOWRITE*/
禁止對查詢塊的查詢重寫操作.
18./*+REWRITE*/
可以將視圖作為參數.
19./*+MERGE(TABLE)*/
能夠對視圖的各個查詢進行相應的合併.
例如:
SELECT/*+MERGE(V) */ A.EMP_NO,A.EMP_NAM,B.DPT_NO FROM BSEMPMS A (SELET DPT_NO
,AVG(SAL) AS AVG_SAL FROM BSEMPMS B GROUP BY DPT_NO) V WHERE A.DPT_NO=V.DPT_NO
AND A.SAL>V.AVG_SAL;
20./*+NO_MERGE(TABLE)*/
對於有可合併的視圖不再合併.
例如:
SELECT/*+NO_MERGE(V) */ A.EMP_NO,A.EMP_NAM,B.DPT_NO FROM BSEMPMS A
(SELECT DPT_NO,AVG(SAL) AS AVG_SAL FROM BSEMPMS B GROUP BY DPT_NO) V
WHERE A.DPT_NO=V.DPT_NO AND A.SAL>V.AVG_SAL;
21./*+ORDERED*/
根據表出現在FROM中的順序,ORDERED使ORACLE依此順序對其連接.
例如:
SELECT/*+ORDERED*/ A.COL1,B.COL2,C.COL3 FROM TABLE1 A,TABLE2 B,TABLE3 C WHERE A.COL1=B.COL1 AND B.COL1=C.COL1;
22./*+USE_NL(TABLE)*/
將指定表與嵌套的連接的行源進行連接,並把指定表作為內部表.
例如:
SELECT/*+ORDERED USE_NL(BSEMPMS)*/
BSDPTMS.DPT_NO,BSEMPMS.EMP_NO,BSEMPMS.EMP_NAM FROM BSEMPMS,BSDPTMS
WHERE BSEMPMS.DPT_NO=BSDPTMS.DPT_NO;
23./*+USE_MERGE(TABLE)*/
將指定的表與其他行源通過合併排序連接方式連接起來.
例如:
SELECT/*+USE_MERGE(BSEMPMS,BSDPTMS)*/ * FROM BSEMPMS,BSDPTMS WHERE BSEMPMS.DPT_NO=BSDPTMS.DPT_NO;
24./*+USE_HASH(TABLE)*/
將指定的表與其他行源通過哈希連接方式連接起來.
例如:
SELECT/*+USE_HASH(BSEMPMS,BSDPTMS)*/ * FROM BSEMPMS,BSDPTMS WHERE BSEMPMS.DPT_NO=BSDPTMS.DPT_NO;
25./*+DRIVING_SITE(TABLE)*/
強制與ORACLE所選擇的位置不同的表進行查詢執行.
例如:
SELECT/*+DRIVING_SITE(DEPT)*/ * FROM BSEMPMS,DEPT@BSDPTMS WHERE BSEMPMS.DPT_NO=DEPT.DPT_NO;
26./*+LEADING(TABLE)*/
將指定的表作為連接次序中的首表.
27./*+CACHE(TABLE)*/
當進行全表掃描時,CACHE提示能夠將表的檢索塊放置在緩衝區緩存中最近最少列表LRU的最近使用端
例如:
SELECT/*+FULL(BSEMPMS) CAHE(BSEMPMS) */ EMP_NAM FROM BSEMPMS;
28./*+NOCACHE(TABLE)*/
當進行全表掃描時,CACHE提示能夠將表的檢索塊放置在緩衝區緩存中最近最少列表LRU的最近使用端
例如:
SELECT/*+FULL(BSEMPMS) NOCAHE(BSEMPMS) */ EMP_NAM FROM BSEMPMS;
29./*+APPEND*/
直接插入到表的最後,可以提高速度.
insert/*+append*/ into test1 select * from test4 ;
30./*+NOAPPEND*/
通過在插入語句生存期內停止並行模式來啟動常規插入.
insert/*+noappend*/ into test1 select * from test4 ;
作为开发人员,每天同步本地代码是个好习惯,但好习惯不代表人人都愿意做,更不用说天天做。
再细致的人也难免会偶尔忘掉,浪费不必要的时间,因此研究了如下脚本,开机即可启动tortoiseCVS来同步代码,
总算省了自己不少事 :)
TortoiseAct.exe CVSUpdate -l 需要更新的文件夹列表(空格分隔)
将以上脚本置于update.bat文件中,并放到tortoise目录下,然后设置开机运行update.bat即可。
gook luck!
70多家大公司、学术机构和高资历技术专家发起了一项旨在向美国政府机构灌输
开源技术优点的行动。Google、RedHat、Novell、Linux、Mozilla、Sun和电子前沿基金会在
OSCON开源会议上宣布了这一消息,并携手创立了
美国开源联盟。此次共同行动的目标是游说美国联邦政府放弃私权代码软件,转而考虑开源软件。顾问委员会成员包括O’Reilly Media总裁蒂姆·奥莱利(Tim O’Reilly)和Linux基金会执行董事吉姆·泽姆林(Jim Zemlin)。
美国开源联盟的大卫·托马斯(David Thomas)说:“软件自由带来的技术”可以使得政府的IT事务调度更加安全、节省成本、便捷,提供了更强的隐私以及消除供应商锁定(vendor lock-in)的能力。”
然而,游说绝非易事,因为在意见请求阶段,小型开源公
司必须得设法达到和微软一样的地位。而且,政府官员过去曾表达过对开源方式的安全担忧。有评论家认为,暴露在光天化日之下的源代码可能会被黑客盯上,招致
风险。不过,也有观点认为开放代码可以在安全有保障的情况下进行。通过摈弃私权软件模型,允许自由访问系统源代码,政府可不再依赖一小部分软件承包商来构
建安全系统,取而代之的是一个完整的、用于布署防御黑客攻击的编程社区。
美国政府最重要的开源项
目之一是同国家安全局(NSA)的合作。国家安全局已经运用开源技术为使用SELinux系统的政府计算机处理多级安全问题。SELinux最初作为
Linux系统的修改版发布,此后在NSA同开源软件商合作应对安全问题的工作中发挥了自己力量。Linux用户最初曾怀疑NSA用此代码库来窥探他们的
电脑,但并没有人在软件中发现“后门”(back doors)。现在,成千上万名政府雇员和Linux用户都使用SELinux保护自己的机器。
另一个成功的开源政府项目是Sunlight Lab的“美国应用”。该项目显示政府开源对公共责任和集体合作解决方案都具有促进作用,在第一年便大获成功。“美国应用”产生了一系列性能不凡的用户生成项目,包括一个呼叫国会议员的火狐插件以及追踪拖延式演说的网站。Sunlight Labs负责人克雷·约翰逊(Clay Johnson)和其他开源创新者在昨天的Google-O’Reilly开源大奖仪式上得到了如潮的赞美。
蒂姆·奥莱利说:“发明不在于它开始时对世界造成了多大影响,而是最终造成了多少。”随着新安全隐患的形成以及建立新数据集的重要性与日俱增,政府在提升为公民服务的过程中需要考虑开源的解决方案。
如果你想为政府开源项目出一份力,请登陆“美国应用2”和美国开源联盟。
泛型是JDK 5.0后出现新概念,泛型的本质是参数化类型,也就是说所操作的数据类型被指定为一个参数。这种参数类型可以用在类、接口和方法的创建中,分别称为泛型类、泛型接口、泛型方法。
泛型类引入的好处不仅在于减少代码量,还在于一提供了编译时期数据类型的检查功能,可以提前预知错误的发生,增加代码安全性,二是减少了强制类型转换。下面定义一个泛型类
Example GenericFX.java
package org;
public class GenericFX<E>
{
private E fx;
public void setFX(E fx)
{
this.fx = fx;
}
public E getFX()
{
return fx;
}
}
在此例中,GenericFX类就是要定义的泛型类,类型变量E是泛型类的类型参数,我们可以使用GenericFX<E>这样的类型名来声明一个泛型类。如
GenericFX<E> fx = new GenericFX<E>(),其中E就是具体的类型, 下面看一个应用泛型类的例子.
Example GenericFXDemo.java
package org;
public class GenericFXDemo
{
public void main(String[] args)
{
GenericFX<Integer> f1 = new GenericFX<Integer>();
GenericFX<Boolean> f2 = new GenericFX<Boolean>();
f1.setFX(new Integer(10));
System.out.println(f1.getFX);//
f2.setFX(new Boolean(true));
System.out.println(f2.getFX);//
}
}
可以看到,f1,f2都是同一泛型类的对象引用,在取得不同参数类型对象时,已不需要实行类型转换.
如果像这样修改一下代码,
f1.setFX(new Integer(10));
Boolean b = f1.getFX();
System.out.println(b); 这里编译就会报错,告诉你这不安全.
泛型类可以定义多个类型参数,像GenericFX<E,F>就要两个类型参数。但是,无论有多少个类型参数,泛型仍然只需要一个类。如上GenericFX<Integer> ,GenericFX<Boolean>都属于同一个泛型类GenericFX,f1,f2都只是该泛型类的一个应用,当然单一的GenericFX类是不能称为泛型类的,必须要有<>和类型参数才可以,而像fx只是泛型类的成员变量。
昨天打开我心爱的xubuntu,发现上下的panel居然不见了,极其郁闷!虽然可以手工启动,但出现了更恼人的问题,xfce启动明显慢了很多,控制台可以看到错误信息“xfce4-panel is not running”.在xinitrc中,可以看到,如果panel启动失败,会重试很多次,这就是启动变慢的元凶了。
查了很多地方都没有得到答案,最后还是在debian社区找到了线索,ubuntu他爸万岁。。。
Hm, after nuking ~/.cache/sessions/, the problem is gone.
As I didn't make a copy beforehand I can longer reproduce the problem, so feel
free to close the bug.
说得很清楚了,只要删除~/.cache/sessions/ 目录下的所有内容就可以了。
此问题我想与xfce的session保存有关。保存session时可能出现了文件损坏,导致这个问题。
如果想一劳永逸,不保存session就好了,从个人经验来讲,保存session并没有太多实用价值。
原文地址:http://aofengblog.blog.163.com/blog/static/631702120083222117768/
Oracle SQL的优化规则:
- 尽量少用IN操作符,基本上所有的IN操作符都可以用EXISTS代替
用IN写出来的SQL的优点是比较容易写及清晰易懂,但是用IN的SQL性能总是比较低的,从ORACLE执行的步骤来分析用IN的SQL与不用IN的SQL有以下区别:
ORACLE
试图将其转换成多个表的连接,如果转换不成功则先执行IN里面的子查询,再查询外层的表记录,如果转换成功则直接采用多个表的连接方式查询。由此可见用
IN的SQL至少多了一个转换的过程。一般的SQL都可以转换成功,但对于含有分组统计等方面的SQL就不能转换了。
Oracle在执行IN子查询时,首先执行子查询,将查询结果放入临时表再执行主查询。而EXIST则是首先检查主查询,然后运行子查询直到找到第一个匹
配项。NOT EXISTS比NOT IN效率稍高。但具体在选择IN或EXIST操作时,要根据主子表数据量大小来具体考虑。
推荐方案:在业务密集的SQL当中尽量不采用IN操作符。
- 不用NOT IN操作符,可以用NOT EXISTS或者外连接+替代
此操作是强列推荐不使用的,因为它不能应用表的索引。
推荐方案:用NOT EXISTS 或(外连接+判断为空)方案代替
- 不用“<>”或者“!=”操作符。对不等于操作符的处理会造成全表扫描,可以用“<” or “>”代替
不等于操作符是永远不会用到索引的,因此对它的处理只会产生全表扫描。
推荐方案:用其它相同功能的操作运算代替,如:
1)a<>0 改为 a>0 or a<0
2)a<>’’ 改为 a>’’
- Where子句中出现IS NULL或者IS NOT NULL时,Oracle会停止使用索引而执行全表扫描。可以考虑在设计表时,对索引列设置为NOT NULL。这样就可以用其他操作来取代判断NULL的操作
IS NULL 或IS NOT NULL操作(判断字段是否为空)
判断字段是否为空一般是不会应用索引的,因为B树索引是不索引空值的。
推荐方案:
用其它相同功能的操作运算代替,如:
1)a is not null 改为 a>0 或a>’’等。
2)不允许字段为空,而用一个缺省值代替空值,如业扩申请中状态字段不允许为空,缺省为申请。
3) 建立位图索引(有分区的表不能建,位图索引比较难控制,如字段值太多索引会使性能下降,多人更新操作会增加数据块锁的现象)
- 当通配符“%”或者“_”作为查询字符串的第一个字符时,索引不会被使用
- 对于有连接的列“||”,最后一个连接列索引会无效。尽量避免连接,可以分开连接或者使用不作用在列上的函数替代。
- 如果索引不是基于函数的,那么当在Where子句中对索引列使用函数时,索引不再起作用。
- Where子句中避免在索引列上使用计算,否则将导致索引失效而进行全表扫描。
- 对数据类型不同的列进行比较时,会使索引失效。
- > 及 < 操作符(大于或小于操作符)
大于或小于操作符一般情况下是不用调整的,因为它有索引就会采用索引查找,但有的情况下可以对它进行优化,如一个表有100万记录,一个数值型字段A,
30万记录的A=0,30万记录的A=1,39万记录的A=2,1万记录的A=3。那么执行A>2与A>=3的效果就有很大的区别了,因为
A>2时ORACLE会先找出为2的记录索引再进行比较,而A>=3时ORACLE则直接找到=3的记录索引。
推荐方案:用“>=”替代“>”。
UNION在进行表链接后会筛选掉重复的记录,所以在表链接后会对所产生的结果集进行排序运算,删除重复的记录再返回结果。实际大部分应用中是不会产生重复的记录,最常见的是过程表与历史表UNION。如:
select * from gc_dfys
union
select * from ls_jg_dfys
这个SQL在运行时先取出两个表的结果,再用排序空间进行排序删除重复的记录,最后返回结果集,如果表数据量大的话可能会导致用磁盘进行排序。
推荐方案:采用UNION ALL操作符替代UNION,因为UNION ALL操作只是简单的将两个结果合并后就返回。
select * from gc_dfys
union all
select * from ls_jg_dfys
LIKE 操作符可以应用通配符查询,里面的通配符组合可能达到几乎是任意的查询,但是如果用得不好则会产生性能上的问题,如LIKE
‘%5400%’ 这种查询不会引用索引,而LIKE
‘X5400%’则会引用范围索引。一个实际例子:用YW_YHJBQK表中营业编号后面的户标识号可来查询营业编号 YY_BH LIKE
‘%5400%’ 这个条件会产生全表扫描,如果改成YY_BH LIKE ’X5400%’ OR YY_BH LIKE ’B5400%’
则会利用YY_BH的索引进行两个范围的查询,性能肯定大大提高。
- SQL书写的影响(共享SQL语句可以提高操作效率)
同一功能同一性能不同写法SQL的影响
如一个SQL在A程序员写的为
Select * from zl_yhjbqk
B程序员写的为
Select * from dlyx.zl_yhjbqk(带表所有者的前缀)
C程序员写的为
Select * from DLYX.ZLYHJBQK(大写表名)
D程序员写的为
Select * from DLYX.ZLYHJBQK(中间多了空格)
以上四个SQL在ORACLE分析整理之后产生的结果及执行的时间是一样的,但是从ORACLE共享内存SGA的原理,可以得出ORACLE对每个SQL
都会对其进行一次分析,并且占用共享内存,如果将SQL的字符串及格式写得完全相同则ORACLE只会分析一次,共享内存也只会留下一次的分析结果,这不
仅可以减少分析SQL的时间,而且可以减少共享内存重复的信息,ORACLE也可以准确统计SQL的执行频率。
推荐方案:不同区域出现的相同的Sql语句,要保证查询字符完全相同,以利用SGA共享池,防止相同的Sql语句被多次分析。
Oracle从下到上处理Where子句中多个查询条件,所以表连接语句应写在其他Where条件前,可以过滤掉最大数量记录的条件必须写在Where子句的末尾。
WHERE子句后面的条件顺序对大数据量表的查询会产生直接的影响,如
Select * from zl_yhjbqk where dy_dj = '1KV以下' and xh_bz=1
Select * from zl_yhjbqk where xh_bz=1 and dy_dj = '1KV以下'
以上两个SQL中dy_dj(电压等级)及xh_bz(销户标志)两个字段都没进行索引,所以执行的时候都是全表扫描,第一条SQL的dy_dj =
'1KV以下'条件在记录集内比率为99%,而xh_bz=1的比率只为0.5%,在进行第一条SQL的时候99%条记录都进行dy_dj及xh_bz的
比较,而在进行第二条SQL的时候0.5%条记录都进行dy_dj及xh_bz的比较,以此可以得出第二条SQL的CPU占用率明显比第一条低。
Oracle从右到左处理From子句中的表名,所以在From子句中包含多个表的情况下,将记录最少的表放在最后。(只在采用RBO优化时有效)
在FROM后面的表中的列表顺序会对SQL执行性能影响,在没有索引及ORACLE没有对表进行统计分析的情况下ORACLE会按表出现的顺序进行链接,
由此因为表的顺序不对会产生十分耗服务器资源的数据交叉。(注:如果对表进行了统计分析, ORACLE会自动先进小表的链接,再进行大表的链接)。
- Order By语句中的非索引列会降低性能,可以通过添加索引的方式处理。严格控制在Order By语句中使用表达式
- 当在Sql语句中连接多个表时,使用表的别名,并将之作为每列的前缀。这样可以减少解析时间
- 多利用内部函数提高Sql效率
- SQL语句索引的利用
- 对操作符的优化(见前面)
- 对条件字段的一些优化
如:
substr(hbs_bh,1,4)=’5400’,优化处理:hbs_bh like ‘5400%’
trunc(sk_rq)=trunc(sysdate), 优化处理:sk_rq>=trunc(sysdate) and sk_rq<trunc(sysdate+1)
如:
ss_df+20>50,优化处理:ss_df>30
‘X’||hbs_bh>’X5400021452’,优化处理:hbs_bh>’5400021542’
sk_rq+5=sysdate,优化处理:sk_rq=sysdate-5
hbs_bh=5401002554,优化处理:hbs_bh=’ 5401002554’,注:此条件对hbs_bh 进行隐式的to_number转换,因为hbs_bh字段是字符型。
ys_df>cx_df,无法进行优化
qc_bh||kh_bh=’5400250000’,优化处理:qc_bh=’5400’ and kh_bh=’250000’
可能引起全表扫描的操作
- 在索引列上使用NOT或者“<>”
- 对索引列使用函数或者计算
- NOT IN操作
- 通配符位于查询字符串的第一个字符
- IS NULL或者IS NOT NULL
- 多列索引,但它的第一个列并没有被Where子句引用
ORACLE在SQL执行分析方面已经比较成熟,如果分析执行的路径不对首先应在数据库结构(主要是索引)、服务器当前性能(共享内存、磁盘文件碎片)、数据库对象(表、索引)统计信息是否正确这几方面分析。
原文地址:http://blog.csdn.net/ForWayfarer/archive/2008/09/20/2955812.aspx
1.struts2怎么实现方法签名(类似于struts1的DispatchAction):在strust.xml中配置如下
<action ... method="register" ></action>
<action ... method="login" ></action>
<action ... method="insert" ></action>
(1)struts2怎么实现分发验证:对应于每个方法签名,可以有相应的validate()方法如下
public void validateRegister()
public void validateLogin()
public void validateInsert()
(2)struts2怎么实现分发验证:对应于每个方法签名,可以有相应的验证框架如下
UserAction-register-validation.xml
UserAction-login-validation.xml
UserAction-insert-validation.xml
2.验证顺序
在struts1中,如果在FormBean中覆盖了validate()方法,让其放回null值,则验证框架(xml验证)就会失效。返回
null则代表验证通过or无需验证;覆盖的validate()方法如果返回super.validate(mapping,request)即调用父
类的validate(mapping,request),验证框架才会起作用。也就是说,如果想让验证框架有效,则不要覆盖validate()方法,
如果除了验证框架验证,你还想在validate()方法中添加一些其他验证,可以覆盖validate()方法,但返回值须为
super.validate(mapping,request)。
在struts2中类似。struts2的执行顺序为:
(1). 首先Struts2对客户端传来的数据进行类型转换;
(2). 类型转换完毕后再进行输入校验,顺序:UserAction-validation.xml -->
UserAction-login-validation.xml --> public void validateLogin(){}
--> public void validate(){};
(3). 如果类型转换和输入校验都没有错误发生,那么进入login()方法/execuet()方法(调用商业逻辑).
注意:如果类型转换不成功,也同样要进行输入校验,所以错误信息打印会将二者的错误信息全部打印出来
3.struts2的错误信息
struts2有两种错误级别:addFieldError和addActionError
addActionError(String anErrorMessage) -- Add an Action-level error
message to this
Action:看源代码对于Action级别的错误信息,实际上是放置在ArrayList中的,action级别的error不会在表单中显示。
addFieldError(String fieldName, String errorMessage) -- Add an
error message for a given
field:看源代码真正存放field级别错误信息的对象是LinkedHashMap,该LinkedHashMap的key是String类型
的,value是ArrayList类型的(addFielderror(String,
ArrayList)),实际上是:LinkedHashMap<String, ArrayList<String>>
errors。field级别的error会在表单中显示。
源代码中还有这样一个方法:public boolean hasErrors() { if (hasActionErrors() ||
hasFieldErrors()) ...} 则返回input页面,表示不论是field级别的还是action级别的,只要错误容器不为空,就返回
到input页面。
另外:struts2验证框架(xml验证)是将错误保存在fielderror中的,而不是actionerror。所以在jsp显示错误时要注意。
4.struts2支持客户端验证,s标签依然支持js事件,所以客户端验证推荐自己写js,不过基本不用struts做客户端验证。此外,s标签即使你不给其设置id属性,s标签也会自动生成一个id(通过查看页面源代码(获得s标签的html代码)可获得),如果你自定义了id,则会将s标签自动生成的id覆盖。
有以下两点理由可以支持这一点:
1.jdk中的类通常写得比较考究
怎么说jdk的实现者都是些相当有才华的人,随便哪个来中国都是顶尖级的。我们自己重新实现jdk中的方法无疑是不明智的。
而且搞了半天去实现个人家已经实现的东西也没啥意思,恐怕要冒重新发明轮子之天下大不韪。真是得不偿失。所以同志们,热情的拥抱jdk吧!
2.java的classloader机制
java的classloader就是传说中的双亲委派模式,无论当前classloader下有没有要载入的类,都要先到最顶层classloader,然后再从上向下。最顶层就是对应jdk的,如果这层找到类,就直接返回,下层classloader就不需要再找了,这就是节省了搜索类的时间。
以上纯属个人见解 ,欢迎不同观点。
原文地址:
http://ostermiller.org/convert_java_outputstream_inputstream.html
如果你曾经使用java IO编程,你会很快碰到这种情况,某个类在OutputStream上创建数据而你需要将它发送给某个需要从输入流读取数据的类。
你很快会被问道,“java中如何将OutputStream转换为InputStream?”
方法一:使用字节数组缓存数据
最简单的方法是用字节数组缓存数据。代码如下:
ByteArrayOutputStream out = new ByteArrayOutputStream();
class1.putDataOnOutputStream(out);
class2.processDataFromInputStream(
new ByteArrayInputStream(out.toByteArray())
);
于是,OutputStream就被转换为InputStream了。
方法二:使用管道
第一种方法的问题是你必须有足够的内存缓存所有数据。你可以使用文件系统缓存更多数据,但无论如何可处理数据的大小还是受到限制。
解决方法是创建一个线程产生数据到PipedOutputStream。当前线程可从中读取数据。
PipedInputStream in = new PipedInputStream();
PipedOUtputStream out = new PipedOutputStream(in);
new Thread(
new Runnable(){
public void run(){
class1.putDataOnOutputStream(out);
}
}
).start();
class2.processDataFromInputStream(in);
方法三:使用循环缓存区
方法二中的两个管道流,实际上管理着一个隐藏的循环缓存区。使用一个显式的循环缓存区更易于理解。CircularBuffers 有如下优点:
一个CircularBuffers类而不是两个管道类。
较于缓存所有数据和额外线程的方法更容易使用。
你可以更改缓存大小而不必受限于管道缓存区1K的固定缓存大小。
多线程情形:
CircularByteBuffer cbb = new CircularByteBuffer();
new Thread(
new Runnable(){
public void run(){
class1.putDataOnOutputStream(cbb.getOutputStream());
}
}
).start();
class2.processDataFromInputStream(cbb.getInputStream());
单线程情形:
// buffer all data in a circular buffer of infinite size
CircularByteBuffer cbb = new CircularByteBuffer(CircularByteBuffer.INFINITE_SIZE);
class1.putDataOnOutputStream(cbb.getOutputStream());
class2.processDataFromInputStream(cbb.getInputStream());