Java Web效能優化之一:減少DAO層的呼叫次數
前言
很簡單的一個問題,一個業務方法,需要先查詢一次得到結果(select),然後再根據查詢的結果進行一次更新(update),通常情況下我們會在DAO層定義兩個介面,一個介面實現查詢,一個介面實現更新,在service層呼叫2次。當然還有一種解決方案,就是僅在DAO層定義一個介面,通過update set select 這種語法去做,這樣呼叫一次就可以完成更新,那麼實際情況我們選用哪一種高效呢?根據我的經驗應該是第二種,但有人說盡量不要寫子查詢,那我就具體寫個test case測試一下效率問題。
Test
package zhsz_service;
import javax.annotation.Resource;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import org.springframework.test.context.web.WebAppConfiguration;
import org.springframework.util.Log4jConfigurer;
import cn.zhsz.service.dao.evaluation.impl.EvaluationDaoImpl;
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = { "classpath*:/spring/spring_servlet.xml",
"classpath*:/spring/spring_config.xml" })
@WebAppConfiguration
public class MainTest {
private static Log logger = LogFactory.getLog(MainTest.class);// 日誌
@Resource(name="evaluationDao")
private EvaluationDaoImpl evaluationDao;
@Test
public void testOne() throws Exception {
long beforeCurrentTimeMillis = System.currentTimeMillis();
float score =this.evaluationDao.findScoreByOid(10);
boolean result = this.evaluationDao.updateOptionScoreByQid("123",5, score);
long afterCurrentTimeMillis = System.currentTimeMillis();
logger.error("testOne用時"+ (afterCurrentTimeMillis - beforeCurrentTimeMillis) + "毫秒!");
}
@Test
public void testTwo() throws Exception {
long beforeCurrentTimeMillis = System.currentTimeMillis();
boolean result = this.evaluationDao.updateOptionScoreByQid("123",5, 9);
long afterCurrentTimeMillis = System.currentTimeMillis();
logger.error("testTwo用時"+ (afterCurrentTimeMillis - beforeCurrentTimeMillis) + "毫秒!");
}
@Before
public void setUp() throws Exception {
Log4jConfigurer.initLogging("classpath:log4j.properties");
}
@After
public void tearDown() throws Exception {
}
}
可以看到,testOne呼叫了2次DAO層,分別是下面這兩條sql:
<select id="findScoreByOid" parameterType="int" resultType="float">
select score from t_evaluation_options where id = #{oid}
</select>
<update id="updateOptionScoreByQid2" parameterType="Map">
update t_self_evaluation set score = #{score}
where stu_number = #{stuNum} and question_id = #{qid}
</update>
而testTwo只呼叫了1次DAO層,但sql是帶子查詢的update set select語法:
<update id="updateOptionScoreByQid" parameterType="Map">
update t_self_evaluation set score =
(select score from t_evaluation_options where id = #{oid})
where stu_number = #{stuNum} and question_id = #{qid}
</update>
現在分別執行這兩個方法8次後得到8組測試介面,最後觀察一下log4j輸出在檔案中的除錯資訊:
2015-11-14 12:25:41 [ main:2529 ] - [ ERROR ] testOne用時578毫秒!
2015-11-14 12:25:51 [ main:1483 ] - [ ERROR ] testTwo用時156毫秒!
2015-11-14 12:26:00 [ main:1469 ] - [ ERROR ] testOne用時172毫秒!
2015-11-14 12:26:07 [ main:1452 ] - [ ERROR ] testTwo用時172毫秒!
2015-11-14 12:26:17 [ main:1530 ] - [ ERROR ] testOne用時235毫秒!
2015-11-14 12:26:25 [ main:1484 ] - [ ERROR ] testTwo用時156毫秒!
2015-11-14 12:26:33 [ main:1531 ] - [ ERROR ] testOne用時173毫秒!
2015-11-14 12:26:41 [ main:1454 ] - [ ERROR ] testTwo用時171毫秒!
2015-11-14 12:26:49 [ main:1547 ] - [ ERROR ] testOne用時204毫秒!
2015-11-14 12:26:57 [ main:1498 ] - [ ERROR ] testTwo用時156毫秒!
2015-11-14 12:27:18 [ main:1468 ] - [ ERROR ] testOne用時187毫秒!
2015-11-14 12:27:57 [ main:1469 ] - [ ERROR ] testTwo用時156毫秒!
2015-11-14 12:28:52 [ main:1498 ] - [ ERROR ] testOne用時202毫秒!
2015-11-14 12:28:59 [ main:1473 ] - [ ERROR ] testTwo用時156毫秒!
2015-11-14 12:29:24 [ main:1531 ] - [ ERROR ] testOne用時189毫秒!
2015-11-14 12:29:31 [ main:1469 ] - [ ERROR ] testTwo用時156毫秒!
可以看到除了第二組用時一樣,其它7組測試資料均是testOne的用時大於testTwo,也就是說即使testTwo的SQL中用了子查詢,依舊比呼叫2次DAO層的效率要高一些。
下面再看一下最後一組測試的完整debug日誌:
首先看一下圖片中的紅色標記,由於TestOne呼叫了兩次DAO,那必然執行了2次SQL,也就是說會有2個PreparedStatement物件,這裡我們用的druid連線池,也就是說會向池裡put兩次,最後再remove兩次,再看一下綠色的標記,可以發現TestOne和TestTwo的效率差距也正是由於兩次put中間的差值,而資料庫的效率差距已經小到無法區分。
總結
所以當我們在寫程式的時候如果遇到複雜的業務方法,可以考慮儘量直接在資料庫層通過複雜sql、function或procedure去處理而避免多次呼叫DAO層的方法,這樣在效率方面應該會有一些提升,如果有不對的地方歡迎批評指正,The End。
相關文章
- [譯]Web 效能優化: 圖片優化讓網站大小減少 62%Web優化網站
- javascript提高效能方式之減少dom元素訪問次數JavaScript
- 前端頁面優化,減少 reflow 的方法前端優化
- informix的效能優化(之一)ORM優化
- 設法減少表掃描次數(luise)UI
- 使用rownum減少函式呼叫函式
- 瀏覽器渲染原理(效能優化之如何減少重排和重繪)瀏覽器優化
- 效能優化-合成層優化
- web效能優化Web優化
- 經過4次優化我把python程式碼耗時減少95%優化Python
- Java Web 前端高效能優化(二)JavaWeb前端優化
- 效能優化漫談之一優化
- Web效能優化系列(1):Web效能優化分析Web優化
- 大幅減少訓練迭代次數,提高泛化能力:IBM提出「新版Dropout」IBM
- web層與DAO層的解耦如何設計合理?Web解耦
- js儘量減少程式碼重複執行的次數JS
- iOS圖層效能優化iOS優化
- Web 頁面優化專項 > Lighthouse > 效能分數優化Web優化
- Web效能優化:圖片優化Web優化
- iOS App優化1---減少包體積iOSAPP優化
- PHP程式應該減少brk呼叫,否則效能會受影響PHP
- web前端效能優化Web前端優化
- Web 效能優化方法Web優化
- 【JS實用技巧】利用冒泡機制,減少事件繫結,優化頁面效能JS事件優化
- 高效能web建站規則(儘量減少http請求)WebHTTP
- 前端巧用localStorage做“快取”,減少HTTP請求次數前端快取HTTP
- Web效能優化之圖片優化Web優化
- Oracle效能優化之“少做事”(rebuild index)Oracle優化RebuildIndex
- java效能優化Java優化
- JAVA開發之簡化Dao層、提高開發效率Java
- JAVA中Action層, Service層 ,model層 和 Dao層的功能區分Java
- Web 效能優化筆記Web優化筆記
- web效能優化(理論)Web優化
- 高效的SQL語句有助於減少資料庫的訪問次數SQL資料庫
- JAVA開發之簡化Dao層、提高開發效率(二)Java
- JAVA開發之簡化Dao層、提高開發效率(三)Java
- 【譯】Google – 使用 webpack 進行 web 效能優化(一):減小前端資源大小GoWeb優化前端
- 【譯】Google - 使用 webpack 進行 web 效能優化(一):減小前端資源大小GoWeb優化前端