第一篇:性能優化課堂筆記和培訓心得
軟件性能優化心得體會
隨著企業級開發平臺諸如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日,我有幸在蘭州交通大學大禮堂聆聽了全國著名教育專家蔣學晶、汪秀梅、武瓊、張龍四位專家的《全國小學語文名師課堂教學展示及研討會》。在兩天的學習中,我領略了他們的課堂教學風采,欣賞了他們的課堂教學藝術,他們的課給我全新的感覺,留給我印象最深的是他們的課是那樣的樸實,那樣的簡單,讓我受益匪淺,為盲目的我指明了今后教學前進的方向。作為一名經驗尚淺的年輕教師,我沒有能力對名師的課進行點評,也無法準確地對名師們所要帶給我們的新理念一一闡述,只能將我在課堂現場的激動與感受記錄下來,現匯報如下:
蔣學晶老師上了兩節,一節是《鳳辣子初見林黛玉》,二節是《臨死前的嚴監生》。他的課最大的特點是設計精心,環環相扣,絲絲入扣,行云流水,滴水不漏。在教學《鳳辣子初見林黛玉》時,蔣老師通過學生提出的課文中最難讀的一段話,也就是描寫鳳辣子著裝的一個段落,讓學生說出你從她的穿著當中可以看出些什么,有些同學說她有錢,有些說有地位,還有的說她愛炫耀,等等。從學生的發言當中,老師抓住了王熙鳳的性格特征,以此突破文章的主要內容以及難點。通過帶著目的層層深入的閱讀,不僅讓學生理解了課文的內容,而且也讓學生學到了新的讀書方法,體會到了學習語文的樂趣。在教學《臨死前的嚴監生》一課時,蔣老師通過一系列的閱讀,以“兩個指頭”為點梳理小說線索,貫穿全文,達到理解人物性格的目的。他在教學中,緊緊抓住課文中主要人物的“吝嗇”和“愛錢”,充分讓學生感受到文中人物的性格及品質特點,那就是見錢眼開、虛情假意、等惡習。同時,他還引導學生分析課文描寫人物時所采用的不同方法,這對學生寫作也能起到很好的促進作用。他這樣的做法讓我對自己在處理這些問題時所采用的方法的思考,我是不是應該改變點什么呢?
古詩教學在小學語文教學中所占的比例不是很大,但它卻是我國的傳統文化,作為語文教師,我們更應該重視古詩教學,以此培養和提高學生的語文素養。但古詩教學又是我們的難點,汪秀梅老師的古詩教學讓我茅塞頓開。她的古詩教學以吟誦為主,讓學生在吟與誦中體會作者的思鄉之情,兵吹膜作者的表達方法。我也初次見識了什么叫吟誦,汪秀梅老師是中華吟誦學會理事,通過她的吟誦,能把孩子們學習古詩的積極性極大的調動起來,讓他們在形式多樣、富有情趣的反復誦讀中,既讀懂詩句的意思,又充分感受到詩的意境,獲得審美的喜悅。課后,他對參會教師進行了簡單的培訓,讓我們初步認識了讀、唱、吟、舞四步教學法的特點,這對我們今后的古詩教學將起到重要的促進作用。
全國著名特級教師武瓊執教的《驚弓之鳥》,其特點是引導學生自己提出問題,她親切的話語,讓學生一下子愛上她的課堂,而且樸實、真實、自然、細致、實在。讓學生在讀中抓住重點詞句理解課文,品析課文后,再讀課文,在讀中感悟。學生在充分的朗讀中,一步步地加深了對課文內容的理解。她在課問的解讀中融入作文的訓練,她的語文教學讓我明白了學生要讀懂課文,教師自身的語文素養也是非常重要的,高素質的教師能通過自己的朗讀和適當的講解感受到文本的情感與寫作方法。
總之,這幾位專家向我們展示了什么是充滿語文味的語文課,那就是“字詞句篇,聽說讀寫”。他們都注重朗讀在教學中的運用,以朗讀來激發學生的情感,幫助學生理解課文,根據課文提供學生口語表達和書面表達的機會,讓學生在“聽說讀寫”上都得到鍛煉。以引導為主,讓學生真正成為課堂的主人。這些都是我應該學習的,上好充滿語文味的語文課也將是我努力的方向。他們的語文課讓我感受到:語文課堂只有在學生閱讀興趣的花朵盛開時,才是最美麗的,才是充滿智慧的!通過兩天的學習,使我學到了許多優秀的先進的教學經驗和教學方法,為我今后的語文教學指明了方向。在以后的工作中,我會理論聯系實際,化感動為行動,將本次學到的好經驗、好方法應用到教育教學工作中,做一個愛孩子、愛語文、愛教育事業的合格的人民教師。