第一篇:性能优化课堂笔记和培训心得
软件性能优化心得体会
随着企业级开发平台诸如J2EE的普及和发展,越来越多的企业应用采用了这些技术作为快速开发平台,但是,这些应用也面临着一些困扰,特别是性能问题。这主要是由这些系统的分布性、复杂性和数据无关性引起的。高性能是软件高质量的重要体现,也是用户满意度提高的重要软件特征,为了提高软件的性能,在这次培训中,老师从以下几个层次讨论软件性能优化。
一、Java底层代码的性能优化
1、首先根据Jvm虚拟机的内存机制来优化系统
堆(Heap)是一个复杂的结构,对象及其成员通常保存在堆中。运行时在数据区, 动态创建,堆中的内容由 GC 负责回收。栈(Stack)是一个简单的结构,方法的参数(基本型别的值、指向对象的引用)通常保存在栈中。栈中的内容在方法执行完时就被回收了。
栈的存取速度比堆要快,栈数据可以共享,存在栈中的数据大小与生存期必须是确定的,栈中主要存放一些基本类型的变量(,int, short, long, byte, float, double, boolean, char)和对象句柄。
使用局部变量的好处在于作用范围是变量定义的方法内部,一旦离开作用域,栈内存将被快速释放,与GC无关,而其他变量,如静态变量、实例变量等,都在堆(Heap)中创建,速度较慢,但是可以自动回收。所以要尽量使用局部变量。在这里,培训的老师举了个人例子 A for(int i=0;i<10000;i++){
Object o = new Object();} B Object o = null;for(int i=0;i<10000;i++){
o = new Object();} A和B之间究竟哪个性能更加好呢?
在这里A和B的唯一区别在于,B在循环体外定义Object,而A是在循环体内定义Object,显然A的Object作用域是在局部,一旦执行下一轮循环,立即释放原先定义的Object,而B的Object作用域是在全局,必须等到循环全部结束,Object才能被释放,因此A的性能要好于B,而且两者运行速度不是一个数量级。
2、需要慎用异常处理机制
因为异常只能用于错误处理,不适合用来控制流程,抛出异常的同时,系统往往会创建一个新的对象,只要有异常被抛出,VM就必须调整调用堆栈,因为在处理过程中创建了一个新的对象。这样对系统的性能会造成一定的影响,因此,要尽量少用自定义的异常抛出机制。
3、使用多线程会提高系统的性能,但是处理多线程的时候,为了防止资源竞争,需要加锁。
一般锁是Synchronized,jdk 1.5 版本多加了个ReetrantLock,我查阅了官方说明:重入锁(ReentrantLock)是一种递归无阻塞的同步机制,它可重入的互斥锁定 Lock,它具有与使用 synchronized 方法和语句所访问的隐式监视器锁定相同的一些基本行为和语义,但功能更强大。ReentrantLock 将由最近成功获得锁定,并且还没有释放该锁定的线程所拥有。当锁定没有被另一个线程所拥有时,调用 lock 的线程将成功获取该锁定并返回。如果当前线程已经拥有该锁定,此方法将立即返回。可以使用 isHeldByCurrentThread()和 getHoldCount()方法来检查此情况是否发生。
虽然 ReentrantLock 是个非常动人的实现,相对 synchronized 来说,它有一些重要的优势,但是我认为急于把 synchronized 视若敝屣,绝对是个严重的错误。java.util.concurrent.lock 中的锁定类是用于高级用户和高级情况的工具。一般来说,除非对 Lock 的某个高级特性有明确的需要,或者有明确的证据(而不是仅仅是怀疑)表明在特定情况下,同步已经成为可伸缩性的瓶颈,否则还是应当继续使用 synchronized。
为什么在一个显然“更好的”实现的使用上主张保守呢?因为对于 java.util.concurrent.lock 中的锁定类来说,synchronized 仍然有一些优势。比如,在使用 synchronized 的时候,不能忘记释放锁;在退出 synchronized 块时,JVM 会为你做这件事。很容易忘记用 finally 块释放锁,这对程序非常有害。你的程序能够通过测试,但会在实际工作中出现死锁,那时会很难指出原因(这也是为什么根本不让初级开发人员使用 Lock 的一个好理由。)
另一个原因是因为,当 JVM 用 synchronized 管理锁定请求和释放时,JVM 在生成线程转储时能够包括锁定信息。这些对调试非常有价值,因为它们能标识死锁或者其他异常行为的来源。Lock 类只是普通的类,JVM 不知道具体哪个线程拥有 Lock 对象。而且,几乎每个开发人员都熟悉 synchronized,它可以在 JVM 的所有版本中工作。在 JDK 5.0 成为标准(从现在开始可能需要两年)之前,使用 Lock 类将意味着要利用的特性不是每个 JVM 都有的,而且不是每个开发人员都熟悉的。
既然如此,我们什么时候才应该使用 ReentrantLock 呢?答案非常简单 —— 在确实需要一些 synchronized 所没有的特性的时候,比如时间锁等候、可中断锁等候、无块结构锁、多个条件变量或者锁投票。ReentrantLock 还具有可伸缩性的好处,应当在高度争用的情况下使用它,但是请记住,大多数 synchronized 块几乎从来没有出现过争用,所以可以把高度争用放在一边。我建议用 synchronized 开发,直到确实证明 synchronized 不合适,而不要仅仅是假设如果使用 ReentrantLock “性能会更好”。请记住,这些是供高级用户使用的高级工具。(而且,真正的高级用户喜欢选择能够找到的最简单工具,直到他们认为简单的工具不适用为止。)。一如既往,首先要把事情做好,然后再考虑是不是有必要做得更快。
4、线程池
创建和销毁线程是非常耗资源的,当服务器同时接受很多请求时,根据操作系统和内存容量,可以创建的线程是有限的,因此需要容易造成内存泄漏,产生异常。因此我们采用线程池技术,Executor创建一个可根据需要创建新线程的线程池,以前构造的线程可用时将重用它们。对于执行很多短期异步任务的程序而言,这些线程池通常可提高程序性能。例,创建20个线程大小的线程池:Executors.newFixedThreadPool(20);
5、原子并发
Hashtable(或者替代方案 Collections.synchronizedMap)的可伸缩性的主要障碍是它使用了一个 map 范围(map-wide)的锁,为了保证插入、删除或者检索操作的完整性必须保持这样一个锁,而且有时候甚至还要为了保证迭代遍历操作的完整性保持这样一个锁。这样一来,只要锁被保持,就从根本上阻止了其他线程访问 Map,即使处理器有空闲也不能访问,这样大大地限制了并发性
6、ConcurrentHashMap摒弃了单一的 map 范围的锁,取而代之的是由 32 个锁组成的集合,其中每个锁负责保护 hash bucket 的一个子集。锁主要由变化性操作(put()和 remove())使用。具有 32 个独立的锁意味着最多可以有 32 个线程可以同时修改 map。绝大多数系统应用绝对够用。并发有32个锁,超过了32个锁就会处于等待状态。ConcurrentLinkedQueue也具有类似的原理。
7、对于对象的操作New, clone, reflection之间的比较
对象生成效率:new一个对象生成的效率高于深clone,深clone效率高于反射 复杂对象(带有数据结构参数,如Map,List),浅clone对象生成的效率高于new一个对象,new一个对象效率高于反射
采用深clone和浅clone效率高,而采用Reflection效率低,因此我们平时编写代码时要尽量少用反射。
8、字符串优化
采用字符串打印out.println()会影响效率,因此需要减少字符串打印 多使用StringBuffer,避免多字符串级联
二、数据库的性能优化
1、对数据库系统进行设置,方便优化,以db2为例,使用 DB2 的自动功能,尤其是 DB2 9 支持的 STMM,以及 DB2 Version 8 和 DB2 9 都支持的 Automatic Maintenance(尤其是自动的 runstats)。这些功能不但会减少监控和维护数据库所需的操作,也能对数据库进行更加有效的调优。
2、死锁检测以及提高锁的并发性能的方法
数据的锁定分为两种方法,第一种叫做悲观锁,第二种叫做乐观锁。什么叫悲观锁呢,悲观锁顾名思义,就是对数据的冲突采取一种悲观的态度,也就是说假设数据肯定会冲突,所以在数据开始读取的时候就把数据锁定住。而乐观锁就是认为数据一般情况下不会造成冲突,所以在数据进行提交更新的时候,才会正式对数据的冲突与否进行检测,如果发现冲突了,则让用户返回错误的信息,让用户决定如何去做
在DB2等很多数据库中,数据的锁定通常采用页级锁的方式,也就是说对一张表内的数据是一种串行化的更新插入机制,在任何时间同一张表只会插1条数据,别的想插入的数据要等到这一条数据插完以后才能依次插入。带来的后果就是性能的降低,在多用户并发访问的时候,当对一张表进行频繁操作时,会发现响应效率很低,数据库经常处于一种假死状态。而Oracle用的是行级锁,只是对想锁定的数据才进行锁定,其余的数据不相干,所以在对Oracle表中并发插数据的时候,基本上不会有任何影响。
在数据库中可以通过改变锁来提高应用程序并发性能。DB2检测死锁采用如下方法
首先建立一个死锁事件监控器db2 connect to sample db2 “create event monitor dlmon for tables, deadlocks with details write to file 'C:dlmon'” mkdir C:dlmon db2 “set event monitor dlmon state 1” 其次等待死锁,第三通过 db2evmon 工具可以获得死锁信息的日志,并且把日志文件导入到本地机器的文件系统当中。在下面一节,我们将详细分析导出的日志文件。db2 connect reset db2evmon-path c:dlmon > c:dlmondllog1.txt Db2结束引起死锁的应用采用如下3种方法:(1)、SELECT AGENT_ID_HOLDING_LK, LOCK_MODE, TABNAME, AGENT_ID FROM SYSIBMADM.LOCKWAITS查找死锁
(2)根据AGENT_ID查出应用程序db2 list application show detail(3)结束引发死锁的应用db2 “force application(id)”
3、sql语句的优化
(1)使用索引来可以更快地遍历表,提高系统速度,但索引不能过量添加,会增加数据库的极大开销。有时候索引不一定能带来速度快,比如用到in,or子句对索引没用处。(2)采用NOT IN会多次扫描表,建议使用EXIST,NOT EXIST,IN,LEFT OUTER JOIN(3)EXISTS要远比IN的效率高。里面关系到full table scan和range scan。几乎将所有的IN操作符子查询改写为使用EXISTS的子查询。
(4)在海量查询时尽量少用格式转换,比如把字符型转换成数字型。
(5)慎用游标。在某些必须使用游标的场合,可考虑将符合条件的数据行转入临时表中,再对临时表定义游标进行操作,这样可使性能得到明显提高。对于一些多表操作,少用游标,在oracle中用临时表比用索引要快,但是在其他操作系统中不一定。
(6)不用“<>”或者“!=”操作符。对不等于操作符的处理会造成全表扫描,可以用“<” or “>”代替
(7)Where子句中出现IS NULL或者IS NOT NULL时,Oracle会停止使用索引而执行全表扫描。可以考虑在设计表时,对索引列设置为NOT NULL(8)当通配符“%”或者“_”作为查询字符串的第一个字符时,索引不会被使用。
(9)Order By语句中的非索引列会降低性能,可以通过添加索引的方式处理。严格控制在Order By语句中使用表达式
三、应用服务器的优化
1、对应用服务器的连接池优化,连接池的增长速度等
2、Web线程等待队列一般情况下应该为0.页面提交的线程请求
weblogic并发的锁机制好,所以访问的速度快。比WebSphere和tomcat都要速度快。
四、表示层的优化
1、html的标记压缩,采用gzip工具压缩
2、尽量采用div来代替table,嵌套table很影响render性能。
五、优化工具的使用 P6Spy & IronTrackSQL SqlDbxPersonal JProfiler HttpAnalyzerFullV4 Fiddler2
通过这次的培训活动,我有了如下收获和体会:
1、开阔了视野,了解了很多新的知识。了解了oracle和db2的差异之处,这是我过去一直想要知道的。
2、在编程技巧方面,学习到了以往都没有注意过得,特别是jvm最底层的性能优化,对我以后应用jfw框架技术处理业务逻辑提供了很好的借鉴。因为框架对底层代码进行了一系列的封装,采用内存堆栈和并发锁的观点去编程,可以减少很多不必要的对系统的开销。
3、拥有了更多的方法和手段来优化系统,在软件的各个层面上都需要做处理来优化系统,或许在某个细节处做处理效果并不突出,但是在各个层面的综合作用下,性能提高会非常明显。
4、学习了性能优化工具,以后开发程序多使用辅助工具,能真正提高效率。
5、因为参加了这次培训,我查阅了很多相关资料,还了解到了很多培训中没有提到内容,更加充实了知识。
6、软件技术的日新月异也促使我要不断更新自己的知识结构,为应对不同体系结构的软件分析与设计做好准备。
第二篇:心得总结:Java性能优化技巧集锦
心得总结:Java性能优化技巧集锦
一、通用篇
“通用篇”讨论的问题适合于大多数Java应用。
1.1 不用new关键词创建类的实例
用new关键词创建类的实例时,构造函数链中的所有构造函数都会被自动调用。但如果一个对象实现了Cloneable接口,我们可以调用它的clone()方法。clone()方法不会调用任何类构造函数。
在使用设计模式(Design Pattern)的场合,如果用Factory模式创建对象,则改用clone()方法创建新的对象实例非常简单。例如,下面是Factory模式的一个典型实现: public static Credit getNewCredit(){ return new Credit();}
改进后的代码使用clone()方法,如下所示: private static Credit BaseCredit = new Credit();public static Credit getNewCredit(){ return(Credit)BaseCredit.clone();}
上面的思路对于数组处理同样很有用。
1.2 使用非阻塞I/O
版本较低的JDK不支持非阻塞I/O API。为避免I/O阻塞,一些应用采用了创建大量线程的办法(在较好的情况下,会使用一个缓冲池)。这种技术可以在许多必须支持并发I/O流的应用中见到,如Web服务器、报价和拍卖应用等。然而,创建Java线程需要相当可观的开销。
JDK 1.4引入了非阻塞的I/O库(java.nio)。如果应用要求使用版本较早的JDK,在这里有一个支持非阻塞I/O的软件包。
请参见Sun中国网站的《调整Java的I/O性能》。
1.3 慎用异常
异常对性能不利。抛出异常首先要创建一个新的对象。Throwable接口的构造函数调用名为fillInStackTrace()的本地(Native)方法,fillInStackTrace()方法检查堆栈,收集调用跟踪信息。只要有异常被抛出,VM就必须调整调用堆栈,因为在处理过程中创建了一个新的对象。
异常只能用于错误处理,不应该用来控制程序流程。
1.4 不要重复初始化变量
默认情况下,调用类的构造函数时,Java会把变量初始化成确定的值:所有的对象被设置成null,整数变量(byte、short、int、long)设置成0,float和 double变量设置成0.0,逻辑值设置成false。当一个类从另一个类派生时,这一点尤其应该注意,因为用new关键词创建一个对象时,构造函数链中的所有构造函数都会被自动调用。
1.5 尽量指定类的final修饰符
带有final修饰符的类是不可派生的。在Java核心API中,有许多应用final的例子,例如java.lang.String。为String类指定final防止了人们覆盖length()方法。
另外,如果指定一个类为final,则该类所有的方法都是final。Java编译器会寻找机会内联(inline)所有的final方法(这和具体的编译器实现有关)。此举能够使性能平均提高50%。
1.6 尽量使用局部变量
调用方法时传递的参数以及在调用中创建的临时变量都保存在栈(Stack)中,速度较快。其他变量,如静态变量、实例变量等,都在堆(Heap)中创建,速度较慢。另外,依赖于具体的编译器/JVM,局部变量还可能得到进一步优化。请参见《尽可能使用堆栈变量》。
1.7 乘法和除法
考虑下面的代码:
for(val = 0;val < 100000;val +=5){ alterX = val * 8;myResult = val * 2;}
用移位操作替代乘法操作可以极大地提高性能。下面是修改后的代码:
for(val = 0;val < 100000;val += 5){ alterX = val << 3;myResult = val << 1;}
修改后的代码不再做乘以8的操作,而是改用等价的左移3位操作,每左移1位相当于乘以2。相应地,右移1位操作相当于除以2。值得一提的是,虽然移位操作速度快,但可能使代码比较难于理解,所以最好加上一些注释。
二、J2EE篇
前面介绍的改善性能技巧适合于大多数Java应用,接下来要讨论的问题适合于使用JSP、EJB或JDBC的应用。
2.1 使用缓冲标记
一些应用服务器加入了面向JSP的缓冲标记功能。例如,BEA的WebLogic Server从6.0版本开始支持这个功能,Open Symphony工程也同样支持这个功能。JSP缓冲标记既能够缓冲页面片断,也能够缓冲整个页面。当JSP页面执行时,如果目标片断已经在缓冲之中,则生成该片断的代码就不用再执行。页面级缓冲捕获对指定URL的请求,并缓冲整个结果页面。对于购物篮、目录以及门户网站的主页来说,这个功能极其有用。对于这类应用,页面级缓冲能够保存页面执行的结果,供后继请求使用。
对于代码逻辑复杂的页面,利用缓冲标记提高性能的效果比较明显;反之,效果可能略逊一筹。
请参见《用缓冲技术提高JSP应用的性能和稳定性》。
2.2 始终通过会话Bean访问实体Bean
直接访问实体Bean不利于性能。当客户程序远程访问实体Bean时,每一个get方法都是一个远程调用。访问实体Bean的会话Bean是本地的,能够把所有数据组织成一个结构,然后返回它的值。
用会话Bean封装对实体Bean的访问能够改进事务管理,因为会话Bean只有在到达事务边界时才会提交。每一个对get方法的直接调用产生一个事务,容器将在每一个实体Bean的事务之后执行一个“装入-读取”操作。
一些时候,使用实体Bean会导致程序性能不佳。如果实体Bean的唯一用途就是提取和更新数据,改成在会话Bean之内利用JDBC访问数据库可以得到更好的性能。
2.3 选择合适的引用机制
在典型的JSP应用系统中,页头、页脚部分往往被抽取出来,然后根据需要引入页头、页脚。当前,在JSP页面中引入外部资源的方法主要有两种:include指令,以及include动作。
include指令:例如<%@ include file=“copyright.html” %>。该指令在编译时引入指定的资源。在编译之前,带有include指令的页面和指定的资源被合并成一个文件。被引用的外部资源在编译时就确定,比运行时才确定资源更高效。
include动作:例如
2.4 在部署描述器中设置只读属性
实体Bean的部署描述器允许把所有get方法设置成“只读”。当某个事务单元的工作只包含执行读取操作的方法时,设置只读属性有利于提高性能,因为容器不必再执行存储操作。
2.5 缓冲对EJB Home的访问
EJB Home接口通过JNDI名称查找获得。这个操作需要相当可观的开销。JNDI查找最好放入Servlet的init()方法里面。如果应用中多处频繁地出现EJB访问,最好创建一个EJBHomeCache类。EJBHomeCache类一般应该作为singleton实现。
2.6 为EJB实现本地接口
本地接口是EJB 2.0规范新增的内容,它使得Bean能够避免远程调用的开销。请考虑下面的代码。PayBeanHome home =(PayBeanHome)javax.rmi.PortableRemoteObject.narrow(ctx.lookup(“PayBeanHome”), PayBeanHome.class);PayBean bean =(PayBean)javax.rmi.PortableRemoteObject.narrow(home.create(), PayBean.class);
第一个语句表示我们要寻找Bean的Home接口。这个查找通过JNDI进行,它是一个RMI调用。然后,我们定位远程对象,返回代理引用,这也是一个 RMI调用。第二个语句示范了如何创建一个实例,涉及了创建IIOP请求并在网络上传输请求的stub程序,它也是一个RMI调用。
要实现本地接口,我们必须作如下修改:
方法不能再抛出java.rmi.RemoteException异常,包括从RemoteException派生的异常,比如 TransactionRequiredException、TransactionRolledBackException和 NoSuchObjectException。EJB提供了等价的本地异常,如TransactionRequiredLocalException、TransactionRolledBackLocalException和NoSuchObjectLocalException。
所有数据和返回值都通过引用的方式传递,而不是传递值。
本地接口必须在EJB部署的机器上使用。简而言之,客户程序和提供服务的组件必须在同一个JVM上运行。
如果Bean实现了本地接口,则其引用不可串行化。
请参见《用本地引用提高EJB访问效率》。
软件资讯 > 开发特区 > 开发语言 > Java
2006年05月11日 作者:songxin 责任编辑:xietaoming
文章导读:分通用篇、J2EE篇、GUI篇三部分介绍Java性能优化技巧。
2.7 生成主键
在EJB之内生成主键有许多途径,下面分析了几种常见的办法以及它们的特点。
利用数据库内建的标识机制(SQL Server的IDENTITY或Oracle的SEQUENCE)。这种方法的缺点是EJB可移植性差。
由实体Bean自己计算主键值(比如做增量操作)。它的缺点是要求事务可串行化,而且速度也较慢。
利用NTP之类的时钟服务。这要求有面向特定平台的本地代码,从而把Bean固定到了特定的OS之上。另外,它还导致了这样一种可能,即在多CPU的服务器上,同一个毫秒之内生成了两个主键。
借鉴Microsoft的思路,在Bean中创建一个GUID。然而,如果不求助于JNI,Java不能确定网卡的MAC地址;如果使用JNI,则程序就要依赖于特定的OS。
还有其他几种办法,但这些办法同样都有各自的局限。似乎只有一个答案比较理想:结合运用RMI和JNDI。先通过RMI注册把RMI远程对象绑定到JNDI树。客户程序通过JNDI进行查找。下面是一个例子: public class keyGenerator extends UnicastRemoteObject implements Remote { private static long KeyValue = System.currentTimeMillis();public static synchronized long getKey()throws RemoteException { return KeyValue++;}
2.8 及时清除不再需要的会话
为了清除不再活动的会话,许多应用服务器都有默认的会话超时时间,一般为30分钟。当应用服务器需要保存更多会话时,如果内存容量不足,操作系统会把部分内存数据转移到磁盘,应用服务器也可能根据“最近最频繁使用”(Most Recently Used)算法把部分不活跃的会话转储到磁盘,甚至可能抛出“内存不足”异常。在大规模系统中,串行化会话的代价是很昂贵的。当会话不再需要时,应当及时调用HttpSession.invalidate()方法清除会话。HttpSession.invalidate()方法通常可以在应用的退出页面调用。
2.9 在JSP页面中关闭无用的会话
对于那些无需跟踪会话状态的页面,关闭自动创建的会话可以节省一些资源。使用如下page指令: <%@ page session=“false”%>
2.10 Servlet与内存使用
许多开发者随意地把大量信息保存到用户会话之中。一些时候,保存在会话中的对象没有及时地被垃圾回收机制回收。从性能上看,典型的症状是用户感到系统周期性地变慢,却又不能把原因归于任何一个具体的组件。如果监视JVM的堆空间,它的表现是内存占用不正常地大起大落。
解决这类内存问题主要有二种办法。第一种办法是,在所有作用范围为会话的Bean中实现HttpSessionBindingListener接口。这样,只要实现valueUnbound()方法,就可以显式地释放Bean使用的资源。
另外一种办法就是尽快地把会话作废。大多数应用服务器都有设置会话作废间隔时间的选项。另外,也可以用编程的方式调用会话的 setMaxInactiveInterval()方法,该方法用来设定在作废会话之前,Servlet容器允许的客户请求的最大间隔时间,以秒计。
2.11 HTTP Keep-Alive
Keep-Alive功能使客户端到服务器端的连接持续有效,当出现对服务器的后继请求时,Keep-Alive功能避免了建立或者重新建立连接。市场上的大部分Web服务器,包括iPlanet、IIS和Apache,都支持HTTP Keep-Alive。对于提供静态内容的网站来说,这个功能通常很有用。但是,对于负担较重的网站来说,这
里存在另外一个问题:虽然为客户保留打开的连接有一定的好处,但它同样影响了性能,因为在处理暂停期间,本来可以释放的资源仍旧被占用。当Web服务器和应用服务器在同一台机器上运行时,Keep-Alive功能对资源利用的影响尤其突出。
2.12 JDBC与Unicode
想必你已经了解一些使用JDBC时提高性能的措施,比如利用连接池、正确地选择存储过程和直接执行的SQL、从结果集删除多余的列、预先编译SQL语句,等等。
除了这些显而易见的选择之外,另一个提高性能的好选择可能就是把所有的字符数据都保存为Unicode(代码页13488)。Java以Unicode形式处理所有数据,因此,数据库驱动程序不必再执行转换过程。但应该记住:如果采用这种方式,数据库会变得更大,因为每个Unicode字符需要2个字节存储空间。另外,如果有其他非Unicode的程序访问数据库,性能问题仍旧会出现,因为这时数据库驱动程序仍旧必须执行转换过程。
2.13 JDBC与I/O
如果应用程序需要访问一个规模很大的数据集,则应当考虑使用块提取方式。默认情况下,JDBC每次提取32行数据。举例来说,假设我们要遍历一个5000 行的记录集,JDBC必须调用数据库157次才能提取到全部数据。如果把块大小改成512,则调用数据库的次数将减少到10次。
在一些情形下这种技术无效。例如,如果使用可滚动的记录集,或者在查询中指定了FOR UPDATE,则块操作方式不再有效。
2.14 内存数据库
许多应用需要以用户为单位在会话对象中保存相当数量的数据,典型的应用如购物篮和目录等。由于这类数据可以按照行/列的形式组织,因此,许多应用创建了庞大的Vector或HashMap。在会话中保存这类数据极大地限制了应用的可伸缩性,因为服务器拥有的内存至少必须达到每个会话占用的内存数量乘以并发用户最大数量,它不仅使服务器价格昂贵,而且垃圾收集的时间间隔也可能延长到难以忍受的程度。
一些人把购物篮/目录功能转移到数据库层,在一定程度上提高了可伸缩性。然而,把这部分功能放到数据库层也存在问题,且问题的根源与大多数关系数据库系统的体系结构有关。对于关系数据库来说,运行时的重要原则之一是确保所有的写入操作稳定、可靠,因而,所有的性能问题都与物理上把数据写入磁盘的能力有关。关系数据库力图减少I/O操作,特别是对于读操作,但实现该目标的主要途径只是执行一套实现缓冲机制的复杂算法,而这正是数据库层第一号性能瓶颈通常总是 CPU的主要原因。
一种替代传统关系数据库的方案是,使用在内存中运行的数据库(In-memory Database),例如TimesTen。内存数据库的出发点是允许数据临时地写入,但这些数据不必永久地保存到磁盘上,所有的操作都在内存中进行。这样,内存数据库不需要复杂的算法来减少I/O操作,而且可以采用比较简单的加锁机制,因而速度很快。
三、GUI篇
这一部分介绍的内容适合于图形用户界面的应用(Applet和普通应用),要用到AWT或Swing。
3.1 用JAR压缩类文件
Java档案文件(JAR文件)是根据JavaBean标准压缩的文件,是发布JavaBean组件的主要方式和推荐方式。JAR档案有助于减少文件体积,缩短下载时间。例如,它有助于Applet提高启动速度。一个JAR文件可以包含一个或者多个相关的Bean以及支持文件,比如图形、声音、HTML 和其他资源。
要在HTML/JSP文件中指定JAR文件,只需在Applet标记中加入ARCHIVE = “name.jar”声明。
请参见《使用档案文件提高 applet 的加载速度》。
3.2 提示Applet装入进程
你是否看到过使用Applet的网站,注意到在应该运行Applet的地方出现了一个占位符?当Applet的下载时间较长时,会发生什么事情?最大的可能就是用户掉头离去。在这种情况下,显示一个Applet正在下载的信息无疑有助于鼓励用户继续等待。
下面我们来看看一种具体的实现方法。首先创建一个很小的Applet,该Applet负责在后台下载正式的Applet:
import java.applet.Applet;import java.applet.AppletStub;import java.awt.Label;import java.awt.Graphics;import java.awt.GridLayout;public class PreLoader extends Applet implements Runnable, AppletStub { String largeAppletName;Label label;public void init(){ // 要求装载的正式Applet largeAppletName = getParameter(“applet”);// “请稍等”提示信息
label = new Label(“请稍等...” + largeAppletName);add(label);} public void run(){ try { // 获得待装载Applet的类
Class largeAppletClass = Class.forName(largeAppletName);// 创建待装载Applet的实例
Applet largeApplet =(Applet)largeAppletClass.newInstance();// 设置该Applet的Stub程序 largeApplet.setStub(this);// 取消“请稍等”信息 remove(label);// 设置布局
setLayout(new GridLayout(1, 0));add(largeApplet);// 显示正式的Applet largeApplet.init();largeApplet.start();} catch(Exception ex){ // 显示错误信息
label.setText(“不能装入指定的Applet”);} // 刷新屏幕 validate();
} public void appletResize(int width, int height){ // 把appletResize调用从stub程序传递到Applet resize(width, height);} }
编译后的代码小于2K,下载速度很快。代码中有几个地方值得注意。首先,PreLoader实现了AppletStub接口。一般地,Applet从调用者判断自己的codebase。在本例中,我们必须调用setStub()告诉Applet到哪里提取这个信息。另一个值得注意的地方是,AppletStub接口包含许多和Applet类一样的方法,但appletResize()方法除外。这里我们把对appletResize()方法的调用传递给了resize()方法。
3.3 在画出图形之前预先装入它
ImageObserver接口可用来接收图形装入的提示信息。ImageObserver接口只有一个方法imageUpdate(),能够用一次repaint()操作在屏幕上画出图形。下面提供了一个例子。public boolean imageUpdate(Image img, int flags, int x, int y, int w, int h){ if((flags & ALLBITS)!=0 { repaint();} else if(flags &(ERROR |ABORT))!= 0){ error = true;// 文件没有找到,考虑显示一个占位符 repaint();} return(flags &(ALLBITS | ERROR| ABORT))== 0;}
当图形信息可用时,imageUpdate()方法被调用。如果需要进一步更新,该方法返回true;如果所需信息已经得到,该方法返回false。
3.4 覆盖update方法
update()方法的默认动作是清除屏幕,然后调用paint()方法。如果使用默认的update()方法,频繁使用图形的应用可能出现显示闪烁现象。要避免在paint()调用之前的屏幕清除操作,只需按照如下方式覆盖update()方法:
public void update(Graphics g){ paint(g);}
更理想的方案是:覆盖update(),只重画屏幕上发生变化的区域,如下所示: public void update(Graphics g){ g.clipRect(x, y, w, h);paint(g);}
3.5 延迟重画操作
对于图形用户界面的应用来说,性能低下的主要原因往往可以归结为重画屏幕的效率低下。当用户改变窗口大小或者滚动一个窗口时,这一点通常可以很明显地观察到。改变窗口大小或者滚动屏幕之类的操作导致重画屏幕事件大量地、快速地生成,甚至超过了相关代码的执行速度。对付这个问题最好的办法是忽略所有“迟到” 的事件。
建议在这里引入一个数毫秒的时差,即如果我们立即接收到了另一个重画事件,可以停止处理当前事件转而处理最后一个收到的重画事件;否则,我们继续进行当前的重画过程。
如果事件要启动一项耗时的工作,分离出一个工作线程是一种较好的处理方式;否则,一些部件可能被“冻结”,因为每次只能处理一个事件。下面提供了一个事件处理的简单例子,但经过扩展后它可以用来控制工作线程。
public static void runOnce(String id, final long milliseconds){ synchronized(e_queue){ // e_queue: 所有事件的集合 if(!e_queue.containsKey(id)){ e_queue.put(token, new LastOne());} } final LastOne lastOne =(LastOne)e_queue.get(token);final long time = System.currentTimeMillis();// 获得当前时间 lastOne.time = time;(new Thread(){public void run(){ if(milliseconds > 0){ try {Thread.sleep(milliseconds);} // 暂停线程 catch(Exception ex){} } synchronized(lastOne.running){ // 等待上一事件结束 if(lastOne.time!= time)// 只处理最后一个事件 return;} }}).start();} private static Hashtable e_queue = new Hashtable();private static class LastOne { public long time=0;public Object running = new Object();}
3.6 使用双缓冲区
在屏幕之外的缓冲区绘图,完成后立即把整个图形显示出来。由于有两个缓冲区,所以程序可以来回切换。这样,我们可以用一个低优先级的线程负责画图,使得程序能够利用空闲的CPU时间执行其他任务。下面的伪代码片断示范了这种技术。Graphics myGraphics;Image myOffscreenImage = createImage(size().width, size().height);
Graphics offscreenGraphics = myOffscreenImage.getGraphics();offscreenGraphics.drawImage(img, 50, 50, this);myGraphics.drawImage(myOffscreenImage, 0, 0, this);
3.7 使用BufferedImage
Java JDK 1.2使用了一个软显示设备,使得文本在不同的平台上看起来相似。为实现这个功能,Java必须直接处理构成文字的像素。由于这种技术要在内存中大量地进行位复制操作,早期的JDK在使用这种技术时性能不佳。为解决这个问题而提出的Java标准实现了一种新的图形类型,即BufferedImage。
BufferedImage子类描述的图形带有一个可访问的图形数据缓冲区。一个BufferedImage包含一个ColorModel和一组光栅图形数据。这个类一般使用RGB(红、绿、蓝)颜色模型,但也可以处理灰度级图形。它的构造函数很简单,如下所示:
public BufferedImage(int width, int height, int imageType)
ImageType允许我们指定要缓冲的是什么类型的图形,比如5-位RGB、8-位RGB、灰度级等。
3.8 使用VolatileImage
许多硬件平台和它们的操作系统都提供基本的硬件加速支持。例如,硬件加速一般提供矩形填充功能,和利用CPU完成同一任务相比,硬件加速的效率更高。由于硬件加速分离了一部分工作,允许多个工作流并发进行,从而缓解了对CPU和系统总线的压力,使得应用能够运行得更快。利用VolatileImage可以创建硬件加速的图形以及管理图形的内容。由于它直接利用低层平台的能力,性能的改善程度主要取决于系统使用的图形适配器。VolatileImage的内容随时可能丢失,也即它是“不稳定的(volatile)”。因此,在使用图形之前,最好检查一下它的内容是否丢失。VolatileImage有两个能够检查内容是否丢失的方法: public abstract int validate(GraphicsConfiguration gc);public abstract Boolean contentsLost();
每次从VolatileImage对象复制内容或者写入VolatileImage时,应该调用validate()方法。contentsLost()方法告诉我们,自从最后一次validate()调用之后,图形的内容是否丢失。
虽然VolatileImage是一个抽象类,但不要从它这里派生子类。VolatileImage应该通过
Component.createVolatileImage()或者 GraphicsConfiguration.createCompatibleVolatileImage()方法创建。
3.9 使用Window Blitting
进行滚动操作时,所有可见的内容一般都要重画,从而导致大量不必要的重画工作。许多操作系统的图形子系统,包括WIN32 GDI、MacOS和X/Windows,都支持Window Blitting技术。Window Blitting技术直接在屏幕缓冲区中把图形移到新的位置,只重画新出现的区域。要在Swing应用中使用Window Blitting技术,设置方法如下: setScrollMode(int mode);
在大多数应用中,使用这种技术能够提高滚动速度。只有在一种情形下,Window Blitting会导致性能降低,即应用在后台进行滚动操作。如果是用户在滚动一个应用,那么它总是在前台,无需担心任何负面影响。
第三篇:优化培训心得
参加《优化培训》心得体会
6月15日下午听了顾问公司金老师的《关于实施管理流程优化培训》,受益良多,通过这次课程的学习,我了解到一个真正有效的流程对企业的重要性。正所谓没有规矩不成方圆,一个企业的运营离不开科学的管理制度和规范的流程体系。环环相扣的作业流程,需要各个部门之间良好协作和配合。使我对公司的作业流程的作用有了更深入的了解和认识。听完此次课程本人对流程优化有了些许见解:
为什么我们要优化流程呢?在我们公司最常用到得流程是“自由流程”,原因很简单,我们处于一个人管人的阶段,没有一个属于自己的系统化流程,老师说这样的流程很容易让我们的效率大大折扣。作为一个基础人员,很能明白这个意思:往往递交的文件要经过很多流程来处理,每个人进来都会发表自己的意见,虽然调动了大家的积极性,但是当整个流程结束的时候,拟稿人的原本意思已经似是而非了。也许系统管人要比人管人要更见效。这也说明了一个固定的优化流程不仅可以减少我们工作中的重复性工作,还可以使管理层从繁琐的日常事务中解脱出来,进而达到提高公司整体工作效率。
优化的流程在实施过程中将人之间的关系转化成了系统、流程与人之间的关系,让每一个人不仅能做正确的事,还能正确地做事。流程优化是以提高工作质量、提高工作效率、降低成本为目的的,流程优化要围绕优化对象要达到的目标进行;在现有的基础上,提出改进后的实施方案,并对其作出评价;针对评价中发现的问题,再次进行改进,直至满意后开始试行,正式实施。
无论是怎样优化的流程,他一定要做到适应企业的发展。也许每个人对讲课内容的理解都不一样,但是只要我们明白和了解现在工作中的短板是什么?只有了解才可以做的取长补短,更进一步。虽然老师只讲了优化流程的一些基本概念和概述了好的流程应该是怎样的,相信大家已经迫切的期待下一堂课的到来。1
第四篇:SQL语句性能优化
我也做了很长时间医疗软件,也写过不少sql优化,没有详细记录下来,个人感觉下面转载的更符合医院医疗软件实际业务,很认可大部分所写的原则,固转载过来,以作借鉴。软件的根本还是在于更细更精,在于从客户的实际使用考虑问题。
性能优化原则1:永远避免困境
利用缓存把字典数据取到中间服务器或是客户端替代直接sql查询,如,门诊医生站把字典下载到客户端,减少执行次数。
一次性取数据到客户端,然后再逐条处理,而不是分次取数据,处理好一条数据再取下一条再处理。例:门诊收费取hjcfmxk例子,原来是一张处方条明细都查询一次,查询后再处理,现改为一次把所有明细都取过来,然后一条条处理
尽量减少光标,看能不能用临时表
性能优化原则2:kiss原则
对于where 条件中的左边可以利用索引的字段Keep it simple stupid,左边尽量避免用函数(substring,isnull,upper,lower),参加计算+,-*/
例子1:select * from ZY_BRFYMXK where substring(zxrq,1,8)='20081212‘
select * from ZY_BRFYMXK where zxrq between '2008121200' and '2008121224' 例子2:
select * from zy_detail_charge where SUBSTRING(patient_id,1,10)=
substring('000005090600',1,10)这句耗时30秒以上
select * from zy_detail_charge where patient_id like substring('000005090600',1,10)+'%' 这句耗时2秒以内
性能优化原则3:尽可能利用到索引
例:select * from ZY_BRFYMXK a(nolock),VW_LSYZK b(nolock)where a.syxh=3 and a.yzxh=b.xh and a.fylb=0
select * from ZY_BRFYMXK a(nolock),VW_LSYZK b(nolock)where a.syxh=3 and a.yzxh=b.xh and a.fylb=0 and b.syxh=3
性能优化原则4:or,避而远之
对于索引字段尽力避免用or,普通字段可以用or,解决要么分解成多个sql,要么用业务规则避免,例:declare @rq1 ut_rq16,@syxh ut_syxh
select @rq1='20081201'
select @syxh=157
性能优化原则5:避免大批量数据取到前台
例: select * from ZY_BRSYK cyrq between ‘20080901’ and ‘20081201‘,对于大医院每天100多人,90天是9000条数据
性能优化原则6:事务,尽可能的短吧
所有计算、对临时表的更新都应但放在事务外,事务中最好只有更新和插入正式表操作.因为事务中产生的锁只有在commit tran是才会释放。
性能优化原则7:热表,留在最后吧
热表是频繁调用的表。如:sf_mzcfk,zy_brfymxk,bq_fyqqk.对于热表尽量放在事务最后:这样锁的时间短。大家都坚持这样,死锁的可能性就小。如果都是热表各个存储过程更新表的顺序应当一样这样可以避免死锁
性能优化原则8:创建临时表一定要避免在事务中作
如create #tempXX(…)
Select * into #tempXX from …
因为创建临时表会锁tempdb的系统表
例:生成#temp1放在事务内外,用sp_lock2 ‘’观察结果
if object_id('tempdb..#temp1','U')is not null
drop table #temp1
begin tran
select * into #temp1 from ZY_BRSYK where ryrq>'20080901‘
select * from #temp1
waitfor delay '00:00:10'
commit
性能优化原则9:大的报表查询避免与正常业务碰撞
如果没有查询服务器,那要在存储过程中限制不能操作加上如:
declare @rq1 ut_rq16,@rq2 ut_rq16,@now ut_rq16
select @rq1=convert(varchar(8),getdate(),112)+'08:00:00'
select @rq1=convert(varchar(8),getdate(),112)+'11:30:00'
select @now=convert(char(8),getdate(),112)+convert(char(8),getdate(),8)
if @now>@rq1 and @now<@rq2
begin
select '上午繁忙时间段不能作此查询'
return
end
性能优化原则10:存储过程避免大的if…else…
这个常出项在业务相同表不同的存储过程中,因为这样常到if …else …原来医技接口中很多这种存储过程,当时把门诊住院业务放在一个存储过程中。这样最大的问题是sql server会根据sql语句来compile存储,这个过程会生成优化计划,决定用那个索引。如果存储过程用到门诊表compile一下,到用到住院表是发现不对,又会compile一下,这样不停compile.compile很号时间要1-2秒,而且一个存储过成在compile是,所有调用这个存储过程的进程都要在排队等候,因为他会独占锁这个存储过程
例:usp_yjjk_getwzxxm_old.sql,后改为:
usp_yjjk_getwzxxm.sql, usp_yjjk_getwzxxm_mz.sql,usp_yjjk_getwzxxm_zy.sql
性能优化原则11:进攻是最好的防守
在普通编程语句对于数据校验总是用防守办法先判断,后再作相应处理。而在sql中先处理再判断性能会好很多。
--更新药品库存。
If exists(select 1 from YK_YKZKC WHERE idm=100 and kcsl>50)
begin
update YK_YKZKC set kcsl=kcsl-50 where idm=100
End
Else begin
rollback tran
Select ‘F库存不够’
return
end
--改为
update YK_YKZKC set kcsl=kcsl-50 where idm=100 and kcsl>50
If @@rowcount<=0
Begin
Rollbakc tran
Select ‘F库存不够’
end
--取未执行的医技项目,日表没有数据就到年表中查找
if exists(select a.* from SF_MZCFK a(nolock),SF_CFMXK b(nolock)
begin
select a.* into #temp1 from SF_MZCFK a(nolock),SF_CFMXK b(nolock)
end
else begin
select a.* into #temp1 from SF_NMZCFK a(nolock),SF_NCFMXK b(nolock)
end
--改为
Insert into #temp1 select a.*
from SF_MZCFK a(nolock),SF_CFMXK b(nolock)
If @@rowcount=0
Begin
Insert into #temp1 select a.*
from SF_NMZCFK a(nolock),SF_NCFMXK b(nolock)
end
性能优化原则12:trig最后的手段
Trig(触发器)的处理的处理机制是满足条件时就会在源语句后面加上trig中的代码进行执行。
它有两个致命的弊端:(1)不清楚有trig的人会对于执行结果感到迷惑。如常有在插入一张表如果主键是indentity的值常取用select @@identity。但如是有trig,tring中有表插入操作,这时的@@identity可能就不是想要的值。(2)trig会束缚选择。如:有一套单据主表和明细表,当明细表的金额更新时,要同步主表的金额,当程序是一条条更新明细时用trig的作法是每当更新一条明细记录时都算一处所有明细表的总金额,再去更新主表的金额。这样有多少条明细就要算多少次,好的作法是不要trig,直接在sql语句中明细更新完明后,一次性算出总金额每条单据的总金额,再更新主表的金额。
对于trig如果有其他手段就一定要避免用trig.性能优化原则13:用户说好才是真的好
1)有时sql语句性能难以优化,但用户对于系统响应速度还是不满意。这时可以从业务分析处理。
如:我们退费模块录入发票号原来是用fph like ‘XXX%’。用户报怨慢,后来改为先用fph=‘XXX’来查,如查不到再fph like ‘XXX%’。这样在绝大部情况下速度都非常快,同时也满足小部分情况下模糊查询的需求。
如:我们的程序要查日表和年表。如果通过日表union表视图去查会非常慢,性能也难以优化。程序改为普通情况下不查年表,用户勾上年表标志时才查年表。
(2)查询统计很多数据时间比较长,就以查询完一部分数据后可以显示这部分数据或是用提示,这样用户清楚系统在作事情也知道大概进度。这样情绪上会好很多。
(3)查询模块常有一进入时也默认一个查询,如果性能好,查询又合用户心意,这种设计非常好,如果性能不好,那就不是好的设计。用户对于进入都困难的模块是没有好感的。
(4)有户的耐心与查询出的记录成正比。用户痛恨等待很久却没有查询出记录。
对于非常慢的查询,如果有些子查询非常快可以先作这样查询以避免查询很久却没有数据出来的情况。如:按病历号查在院病人所有费有明细,可以先查一下这个病历是不是有对应病人。
实战技巧1:用exists、in代替distinct
Distinct实际上是先收集再删除这样两步都耗资源。
Exists,in会隐式过滤掉重复的记录
例查自2009年以来有金额大于100的药品的病人
select distinct a.blh,a.hzxm from ZY_BRXXK a(nolock),ZY_BRSYK b(nolock),ZY_BRFYMXK c(nolock)where a.patid=b.patid and b.syxh=c.syxh and c.zxrq>'2009' and c.zje>100--改为
select a.blh,a.hzxm from ZY_BRXXK a where exists(select 1 from ZY_BRSYK
b(nolock),ZY_BRFYMXK c(nolock)where a.patid=b.patid and b.syxh=c.syxh and
c.zxrq>'2009'and c.zje>100)
实战技巧2:缩短union
select …from A,B,C,D,E1
where(E1的条件)
and(其他表联接条件)
union
select …from A,B,C,D,E2
where(E2的条件)
and(其他表接接条件)
改为
select …from A,B,C,D,(select...from E1where(E1条件)
union
select …from E2where(E2条件))E where(其他条件)
当涉及ABCD表部分耗资源而E1,E2不耗资源时是这样,如果反过来则改后的性能不一定好。查2009年4月后入院的在院病人在2905病区发生的所有费用明细
select a.hzxm,b.cyrq,d.ypmc,d.ypgg,c.ypsl/c.dwxs ypsl, c.ypdw
select a.hzxm,b.cyrq,d.ypmc,d.ypgg,c.ypsl/c.dwxs ypsl, c.ypdw
from ZY_BRXXK a(nolock),ZY_BRSYK b(nolock),ZY_BRFYMXK c(nolock),YK_YPCDMLK d where a.patid=b.patid and b.ryrq>'200904' and b.brzt not in(3,8,9)and b.syxh=c.syxh and c.bqdm='2905' and c.idm=d.idm
union all
select a.hzxm,b.cyrq,d.name,d.xmgg,c.ypsl/c.dwxs ypsl, c.ypdw
from ZY_BRXXK a(nolock),ZY_BRSYK b(nolock),ZY_BRFYMXK c(nolock),YY_SFXXMK d where a.patid=b.patid and b.ryrq>'200904' and b.brzt not in(3,8,9)and b.syxh=c.syxh and c.bqdm='2905' and c.ypdm=d.id and c.idm=0
--改为
select a.hzxm,b.cyrq,d.ypmc,d.ypgg,c.ypsl/c.dwxs ypsl, c.ypdw
from ZY_BRXXK a(nolock),ZY_BRSYK b(nolock),ZY_BRFYMXK c(nolock),(select ypmc,ypgg,ypdm,idm idm from YK_YPCDMLK union select name,xmgg,id,0 from YY_SFXXMK)d
where a.patid=b.patid and b.ryrq>'200904' and b.brzt not in(3,8,9)and b.syxh=c.syxh and c.bqdm='2905' and c.idm=d.idm and c.ypdm=d.ypdm
实战技巧3:合并sql
把表和where条件类似的两个或是多个sql合并为一个sql.--查2009年以后的普通、急诊、专家挂号人数
declare @ptghs int,@jzghs int,@zjghs int
select @ptghs=0,@jzghs=0,@zjghs=0
select @ptghs=count(*)from GH_GHZDK where ghrq>'2009' and ghlb=0
select @jzghs=count(*)from GH_GHZDK where ghrq>'2009' and ghlb=1
select @zjghs=count(*)from GH_GHZDK where ghrq>'2009' and ghlb=2
select @ptghs,@jzghs,@zjghs
--改为
select @ptghs=0,@jzghs=0,@zjghs=0
select @ptghs=sum(case when ghlb=0 then 1 else 0 end),@jzghs=sum(case when ghlb=1 then 1 else 0 end), @zjghs=sum(case when ghlb=2 then 1 else 0 end)
from GH_GHZDK where ghrq>'2009'
select @ptghs,@jzghs,@zjghs
实战技巧4:去掉游标
把游标当作编程语言的for,do---while的方式,很多情况下都可以去掉,如果光标中间sql语句只有一条一般都是可以去掉光标改为一句sql。
--查当天出院出院日期在2009年4月1到9日间病人的zfdj,zfje置为0
declare @syxh ut_syxh
declare cur1 cursor for select syxh from ZY_BRSYK where cyrq>='20090401' and cyrq<'20090410'
open cur1
fetch cur1 into @syxh
while @@fetch_status=0
begin
fetch cur1 into @syxh
end
close cur1
deallocate cur1
--改为
update ZY_BRFYMXK set zfdj=0,zfje=0
from ZY_BRFYMXK a,ZY_BRSYK b
where a.syxh=b.syxh and b.cyrq>='20090401' and b.cyrq<'20090410'
实战技巧5:取代count
利用内部函数代替
declare @count int
select * into #tmep1 from ZY_BRFYMXK WHERE zxrq>'200901'
select @count=@@rowcount—可以得到count值
select @count
select @count=count(*)from #tmep1—可以被取代
select @count
利用exists而不count判断有没有记录
declare @count int
Select @count=count(1)from ZY_BRFYMXK WHERE zxrq>'2009‘
If @count>0 … else ….--改为
If exists(Select 1 from ZY_BRFYMXK WHERE zxrq>'2009’)… else ….
第五篇:经典课堂培训心得
参加小学语文名师课堂教学展示及研讨会心得体会
治平中心小学:杨菲菲
3月17日至3月18日,我有幸在兰州交通大学大礼堂聆听了全国著名教育专家蒋学晶、汪秀梅、武琼、张龙四位专家的《全国小学语文名师课堂教学展示及研讨会》。在两天的学习中,我领略了他们的课堂教学风采,欣赏了他们的课堂教学艺术,他们的课给我全新的感觉,留给我印象最深的是他们的课是那样的朴实,那样的简单,让我受益匪浅,为盲目的我指明了今后教学前进的方向。作为一名经验尚浅的年轻教师,我没有能力对名师的课进行点评,也无法准确地对名师们所要带给我们的新理念一一阐述,只能将我在课堂现场的激动与感受记录下来,现汇报如下:
蒋学晶老师上了两节,一节是《凤辣子初见林黛玉》,二节是《临死前的严监生》。他的课最大的特点是设计精心,环环相扣,丝丝入扣,行云流水,滴水不漏。在教学《凤辣子初见林黛玉》时,蒋老师通过学生提出的课文中最难读的一段话,也就是描写凤辣子着装的一个段落,让学生说出你从她的穿着当中可以看出些什么,有些同学说她有钱,有些说有地位,还有的说她爱炫耀,等等。从学生的发言当中,老师抓住了王熙凤的性格特征,以此突破文章的主要内容以及难点。通过带着目的层层深入的阅读,不仅让学生理解了课文的内容,而且也让学生学到了新的读书方法,体会到了学习语文的乐趣。在教学《临死前的严监生》一课时,蒋老师通过一系列的阅读,以“两个指头”为点梳理小说线索,贯穿全文,达到理解人物性格的目的。他在教学中,紧紧抓住课文中主要人物的“吝啬”和“爱钱”,充分让学生感受到文中人物的性格及品质特点,那就是见钱眼开、虚情假意、等恶习。同时,他还引导学生分析课文描写人物时所采用的不同方法,这对学生写作也能起到很好的促进作用。他这样的做法让我对自己在处理这些问题时所采用的方法的思考,我是不是应该改变点什么呢?
古诗教学在小学语文教学中所占的比例不是很大,但它却是我国的传统文化,作为语文教师,我们更应该重视古诗教学,以此培养和提高学生的语文素养。但古诗教学又是我们的难点,汪秀梅老师的古诗教学让我茅塞顿开。她的古诗教学以吟诵为主,让学生在吟与诵中体会作者的思乡之情,兵吹膜作者的表达方法。我也初次见识了什么叫吟诵,汪秀梅老师是中华吟诵学会理事,通过她的吟诵,能把孩子们学习古诗的积极性极大的调动起来,让他们在形式多样、富有情趣的反复诵读中,既读懂诗句的意思,又充分感受到诗的意境,获得审美的喜悦。课后,他对参会教师进行了简单的培训,让我们初步认识了读、唱、吟、舞四步教学法的特点,这对我们今后的古诗教学将起到重要的促进作用。
全国著名特级教师武琼执教的《惊弓之鸟》,其特点是引导学生自己提出问题,她亲切的话语,让学生一下子爱上她的课堂,而且朴实、真实、自然、细致、实在。让学生在读中抓住重点词句理解课文,品析课文后,再读课文,在读中感悟。学生在充分的朗读中,一步步地加深了对课文内容的理解。她在课问的解读中融入作文的训练,她的语文教学让我明白了学生要读懂课文,教师自身的语文素养也是非常重要的,高素质的教师能通过自己的朗读和适当的讲解感受到文本的情感与写作方法。
总之,这几位专家向我们展示了什么是充满语文味的语文课,那就是“字词句篇,听说读写”。他们都注重朗读在教学中的运用,以朗读来激发学生的情感,帮助学生理解课文,根据课文提供学生口语表达和书面表达的机会,让学生在“听说读写”上都得到锻炼。以引导为主,让学生真正成为课堂的主人。这些都是我应该学习的,上好充满语文味的语文课也将是我努力的方向。他们的语文课让我感受到:语文课堂只有在学生阅读兴趣的花朵盛开时,才是最美丽的,才是充满智慧的!通过两天的学习,使我学到了许多优秀的先进的教学经验和教学方法,为我今后的语文教学指明了方向。在以后的工作中,我会理论联系实际,化感动为行动,将本次学到的好经验、好方法应用到教育教学工作中,做一个爱孩子、爱语文、爱教育事业的合格的人民教师。