NO.29 | 2018.01.16
banner
title資訊百科 友善列印>>
Java Introduction & Performance Tuning Example_應用服務組 吳宗儒 副工程師



一提到Java,很多人第一個想到的應該是它可以跨平台的特性,但實際上到底是怎麼做到的呢?主要就是透過JVM(Java Virtual Machine),它的存在可以使得各種作業系統能夠順利的接受Java編譯後的檔案,因為各個作業系統的差異性非常大,譬如Windows、Unix、MacOS等等,而JVM的存在就是為了撫平這種差異。

Java的另外一個特性是其物件導向的語言模型可以支持使用物件導向的思考方式來撰寫程式,例如您可以使用 Java 語言定義一個類別去對應一個資料庫的Table,使用 Java 語言來實現繼承的機制等。了解物件導向的精神並以物件導向的方式來設計、撰寫程式並不容易,而且需要經驗的累積,在學習 Java 語言的同時,必須同時學習物件導向的思考方式,如此學來才可以事半功倍。初學者可藉由許多書本中的程式,並從有經驗的開發人員所撰寫的專案中觀摩學習,慢慢了解物件導向的精髓。

在寫一些專案例如:Web或是App常會依照邏輯與DB做聯繫並對相關資料新刪修查,這邊以Oracle為主要討論對象。在建立連線時以最簡單的連線方式,通常是使用JDBC連線,另外有使用相關framework例如:Hibernate、MyBatis、SpringMVC也是不同的連線方式,執行速度的部份則是後續會談到。以上方法都可以對DB做Access,但依據不同的專案考量,專案的大小、功能多寡、SQL的複雜度甚至是對專案的效率需求等,可選擇對開發團隊最方便的方式執行。

這邊以一個資料量近千萬筆的程式來跟大家說明執行的效率,以下是大致上的邏輯以及程式撰寫方向:

1.     執行SELECT COUNT計算SQL會產生多少筆數
2.     執行原本的SQL將所產生的資料取回
3.     依照邏輯將SQL所產生的資料編排後產生成檔案

圖一
 
看完之後首先要做的是在腦海中想這個要怎麼解決,最快的方式就是用圖解如圖一,可以看到首先程式內容先執行SQL取得總筆數再將SQL所撈出的資料一次性取回,接著依照業務邏輯產生檔案。如果這是筆數非常少的檔案,我相信大家都會想盡各種方法去寫,譬如:執行一個SQL產生出資料,把所有資料copy paste到excel檔上,再利用excel的便利性將檔案組成想要的格式,或是寫個PL/SQL直接在DB執行,並產生檔案在DB本機端,可以執行這種功能的方式百百種,但如果有時間限制時,就需要慎選工具,以下則是以Java程式語言解決這項工作。

一開始寫這支程式時,單純是使用JDBC去連線,然後呼叫SQL去執行,用ResultSet去接SQL執行完回傳所需資料,再用一個while Loop將每一筆資料取出並格式化後再寫進一個檔案中。整個程式很簡單,只考慮到執行的成功與否以及資料的正確性,並不在乎執行效率。譬如這支程式一開始寫的時候可能跑了接近4小時,但是由於作業上的需求需要將時間壓縮在10分鐘以內,這時要考慮的重點就有幾個:
1.     SQL的次數是不是可以減少
2.     SQL的執行時間是不是可以再調整的更少一點
3.     產生格式時是否可以減少I/O執行時間
4.     是否有任何Java端執行參數可以影響SQL執行效率或減少SQL執行次數

經過一段時間Tuning之後,提供一個執行速度較快的方式僅供參考,針對原程式執行時間太長的修改方式如下:
1.     利用Java ResultSet的特性,可透過Cursor取得最後一筆資料算得總數,並減少一次SQL的執行。
2.     使用Hint增快SQL執行速度
3.     產生格式的While迴圈中先將結果分別assign給特定物件,避免在判斷時再把結果從ResultSet撈出來造成物件產生進而影響執行效率。
4.     設定Statement每次撈取SQL量的參數,但是這個數字需要經過Tuning,並不是越大越好。
5.     由於I/O是最花時間的部份,所以在寫檔案的時候會利用Buffered Writer並設定buffer參數。

經過這幾項的修正之後,由原本的速度如老人工作一般需要花數個小時,進展到執行速度只需1-2分鐘,好比年輕人跑步衝刺的有感進步差異。如果有使用到其他Framework的話,其實是會影響到SQL執行後寫入的效率,大部分是因為Framework會將SQL撈回來的值再依照物件的關係將值先塞進對應的物件參數中。這支程式其實還可以更快,但我相信以大部分所需的作業時間,如果能縮減至1-2分鐘已經是足夠的了,再調整下去會不敷開發成本。