標籤:mysql java 系統訊息 效能最佳化
從前有個大師,率領一群徒弟,為客戶做了一個軟體系統。某天,客戶提出了一個新的需求,向系統中的所有使用者發送系統訊息。由於當時系統剛上線不久,系統中的使用者也就幾十個。大師為了考驗自己的徒弟,便將該需求分配給他的徒弟,要求每個人都做一套方案出來,於是便有了下面的故事。
徒弟們接收到該項任務後,每個人都想到了先建一張系統訊息表,每次發送系統訊息時,將資料儲存在詞表中,使用者就能從該表中讀取他個人的系統訊息。使用者資訊表的模型如下:
650) this.width=650;" src="http://s3.51cto.com/wyfs02/M02/54/7F/wKiom1SE7u-CszJkAAEpCtm5nzk125.jpg" title="sys_message.png" alt="wKiom1SE7u-CszJkAAEpCtm5nzk125.jpg" />
基於上面的資料庫模型,徒弟們分別作了不同的實現方案,如下:
實現方案一:
小A是個急性子,領到任務後。立即開始了他的編程思路:將系統中的所有使用者都取出來,然後遍曆所有的使用者,每次迭代時插入一條系統訊息。虛擬碼如下:
List<FavUser> userList = favUserService.getAllUser();for(FavUser favUser : userList){ SysMessage sysMessage = new SysMessage(); ... sysMessage.setReceiveUserId(favUser.getUserId()); sysMessageService.addSysMessage(sysMessage);}
由於系統中的使用者較少,小A幾遍測試,發現系統中運行良好,便將該方案提交了上去。
實現方案二:
小B接到任務後,想到應該先把系統中所有的使用者Ids取出來,然後遍曆這些ids,每次迭代時都插入一條系統訊息。基於此,小B的虛擬碼如下:
List<Integer> userIdsList = favUserService.getAllUserIds();for(Integer userId : userIdsList ){ SysMessage sysMessage = new SysMessage(); ... sysMessage.setReceiveUserId(userId); sysMessageService.addSysMessage(sysMessage);}
由於系統中的使用者較少,小B幾遍測試,發現系統中運行良好,也將該方案提交了上去。
實現方案三:
小C接到任務後,考慮到每次插入的系統訊息,除了使用者id不同外,其餘的資料項目都相同,便想到了批量插入資料。由於MySQL資料庫支援批量插入資料,小C設計出了執行的SQL語句與虛擬碼:
執行的SQL語句如下:
<insert id="addBatchSysMessage" parameterType="com.favccxx.favsoft.SysMessage" > insert into sys_message (MESSAGE_TITLE, MESSAGE_CONTENT, MESSAGE_STATUS, RECEIVE_USER_ID, RECEIVE_TIME, CREATE_TIME ) values <foreach collection="list" item="item" index="index" separator=","> ( #{item.messageTitle,jdbcType=VARCHAR},#{item.messageContent,jdbcType=VARCHAR}, #{item.messageStatus,jdbcType=CHAR}, #{item.receiveUserId,jdbcType=INTEGER},#{item.receiveTime,jdbcType=TIMESTAMP}, #{item.createTime,jdbcType=TIMESTAMP} ) </foreach> </insert>
虛擬碼如下:
List<FavUser> userList = favUserService.getAllUser();List<SysMessage> dataList = new ArrayList<SysMessage>();for(FavUser favUser : userList){ sysMessage.setReceiveUserId(favUser.getUserId()); dataList.add(sysMessage);}List<SysMessage> subList = dataList.subList(0,1000);sysMessageService.addBatchSysMessage(subList);
小C向系統中添加了幾千個類比使用者,測試系統運行良好。但發現將系統中的使用者增加至幾萬時,發送系統訊息速度明顯變慢。於是,小C採用了分組的方式進行插入,每10,000條插入一次,系統運行良好。
實現方案四
小D接到任務後,考慮的也是批量插入資料,但與小C不同的是,他想通過執行一次SQL完成批量插入資料。即先將待發送的訊息存入資料庫中,然後通過MySQL查詢並同時將資料插入系統訊息。小D的MySQL設計如下:
<insert id="addAllSysMessage" parameterType="com.favccxx.favsoft.SysMessage" > insert into sys_message ( MESSAGE_TITLE, MESSAGE_CONTENT, MESSAGE_STATUS, RECEIVE_USER_ID, RECEIVE_TIME, CREATE_USER_ID, CREATE_TIME ) select a.MESSAGE_TITLE as MESSAGE_TITLE, a.MESSAGE_CONTENT as MESSAGE_CONTENT, 0 as MESSAGE_STATUS, b.user_id AS RECEIVE_USER_ID, now() as RECEIVE_TIME, now() as CREATE_TIME from sys_message_send_info a, ( select user_id FROM auth_user ) b where sendInfoId=#{sendInfoId} </insert>
int insertCount = sysMessageService.addAllSysMessage(sendInfoId);
小D向系統中插入了10萬個類比使用者,經測試,系統運行良好。以下是向113508個使用者發送訊息的花費時間。
“可愛 的測試”發送給系統中【113508】個使用者,共用時【2241】毫秒 “fdgsdfg”發送給分組中【113508】個使用者,共用時【2236】毫秒 “平台所有使用者系統訊息”發送給系統中【113508】個使用者,共用時【1916】毫秒 “發生的飛灑的”發送給系統中【113508】個使用者,共用時【1217】毫秒 “測試使用者組33”發送給分組中【113508】個使用者,共用時【1617】毫秒 |
上面的故事,便是我們在開發中經常遇到的情境,要實現系統中的一個功能時,往往有很多種方法,最先實現的,代碼最簡便的並不一定是效率最好的。代碼本身就是一個黑盒子,不要考慮程式的現有效能,更要考慮好程式的擴充性能。
本文出自 “塵風隨影的天空” 部落格,請務必保留此出處http://favccxx.blog.51cto.com/2890523/1587394
MySQL案例分享之系統訊息