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優化網站
- 前端頁面優化,減少 reflow 的方法前端優化
- web效能優化Web優化
- 效能優化漫談之一優化
- Web 頁面優化專項 > Lighthouse > 效能分數優化Web優化
- O(1)緯度減少迴圈次數
- 經過4次優化我把python程式碼耗時減少95%優化Python
- 瀏覽器渲染原理(效能優化之如何減少重排和重繪)瀏覽器優化
- Web 效能優化方法Web優化
- web前端效能優化Web前端優化
- 大幅減少訓練迭代次數,提高泛化能力:IBM提出「新版Dropout」IBM
- PHP程式應該減少brk呼叫,否則效能會受影響PHP
- java效能優化Java優化
- web效能優化(理論)Web優化
- Web 效能優化筆記Web優化筆記
- JAVA開發之簡化Dao層、提高開發效率Java
- iOS App優化1---減少包體積iOSAPP優化
- 從一次效能優化看https的效能優化HTTP
- [java][效能優化]java高階開發必會的50個效能優化Java優化
- Withings:2020年全球人們走路的次數減少 但體重卻減輕了
- 我所知道的 Web 效能優化策略Web優化
- web效能常見優化技巧Web優化
- JAVA開發之簡化Dao層、提高開發效率(二)Java
- 前端巧用localStorage做“快取”,減少HTTP請求次數前端快取HTTP
- 【譯】Google – 使用 webpack 進行 web 效能優化(一):減小前端資源大小GoWeb優化前端
- 【譯】Google - 使用 webpack 進行 web 效能優化(一):減小前端資源大小GoWeb優化前端
- web下的效能優化1(網路方向)Web優化
- WEB前端效能優化常見方法Web前端優化
- 輕鬆實現 Web 效能優化Web優化
- 打個總結:Web效能優化Web優化
- 使用Webpack4優化Web效能Web優化
- Web效能優化之瘦身祕笈Web優化
- JAVA效能優化思路探究Java優化
- 【Java效能優化思路方向】Java優化
- 一次 Flutter WebView 效能優化FlutterWebView優化
- ? 記一次前端效能優化前端優化
- 怎麼減少行鎖對效能的影響?
- Oracle效能優化方法論的發展之一:基於區域性命中率分析的效能優化方法Oracle優化
- 移動spa商城優化記(二)--- 減少70%的打包等待時間優化