優惠券項目三

整體項目介紹:

https://blog.csdn.net/wenjieyatou/article/details/80190886

優惠券項目一介紹:

https://blog.csdn.net/wenjieyatou/article/details/80191083

優惠券項目二介紹:

https://blog.csdn.net/wenjieyatou/article/details/80203860

下面是優惠券項目三介紹:

分支1.3

目的:通過程序代碼和優化數據庫來提高性能
具體方案:

1:以前獲取券組下所有的優惠券修改爲獲取100條(經測試統計得出發送50張券消耗時間是106s,每次獲取優惠券大約耗時是2s多,整體性能提升近3倍)

   /**
     * 獲取券組下優惠券
     * @param vendorId
     * @param actNo
     * @param groupNo
     * @param type
     * @return
     */
    private List<Coupon> getCoupons(Long vendorId,String actNo,String groupNo,int type) {
        Coupon coupon = new Coupon();
        coupon.setVendorId(vendorId);
        coupon.setActNo(actNo);
        coupon.setSubgroupCode(groupNo);
        coupon.setState(type);
        coupon.setPageIndex(0);
       //限制獲取數量爲100。
        coupon.setPageSize(100);
        String key = String.format("%s_%s_%s", vendorId, actNo, groupNo);
        List<Coupon> coupons = new ArrayList<>();
        if (couponMap.get(key) != null) {
            coupons = (List<Coupon>) couponMap.get(key);
        }
        if (couponMap.get(key) == null) {
            coupons = couponDao.getCouponListByPage(coupon);
            if (CollectionUtils.isNotEmpty(coupons)) {
                couponMap.put(key, coupons);
            }
        }
        return coupons;
    }

2:優化sql,加入組合索引(統計得出發送50張優惠券消耗總時間是2.5s,每次獲取優惠券大約耗時是0.015s,整體的性能提升了近42倍)

組合優化參考:https://blog.csdn.net/u013628152/article/details/51550923

再談SQL優化:組合索引

對於任何DBMS,索引都是進行優化的最主要的因素。對於少量的數據,沒有合適的索引影響不是很大,但是,當隨着數據量的增加,性能會急劇下降。
如果對多列進行索引(組合索引),列的順序非常重要,MySQL僅能對索引最左邊的前綴進行有效的查找。例如:
假設存在組合索引(c1,c2),查詢語句select * from t1 where c1=1 and c2=2能夠使用該索引。查詢語句select * from t1 where c1=1也能夠使用該索引。但是,查詢語句select * from t1 where c2=2不能夠使用該索引,因爲沒有組合索引的引導列,即,要想使用c2列進行查找,必需出現c1等於某值。

舉例說明:
創建兩張表book(圖書表)和bookclass(圖書分類表)

select b.ISBN FROM book b where b.CATEGORY_ID = 1;

這裏寫圖片描述
執行時間爲:0.053s

使用explain來分析一下該SQL:

這裏寫圖片描述
type = ALL Extra=Using where,全表查詢沒有使用索引。

explain顯示了mysql如何使用索引來處理select語句以及連接表。可以幫助選擇更好的索引和寫出更優化的查詢語句。

ALL 對於每個來自於先前的表的行組合,進行完整的表掃描。如果表是第一個沒標記const的表,這通常不好,並且通常在它情況下很差。通常可以增加更多的索引而不要使用ALL,使得行能基於前面的表中的常數值或列值被檢索出。

創建組合索引:
create index index_isbn on book (CATEGORY_ID,ISBN) ;

再次執行SQL,發現時間縮短到0.009s

這裏寫圖片描述
使用explain來分析一下該SQL:
這裏寫圖片描述
type = ref,Extra = Using index 使用了索引查詢。

ref 對於每個來自於前面的表的行組合,所有有匹配索引值的行將從這張表中讀取。如果聯接只使用鍵的最左邊的前綴,或如果鍵不是UNIQUE或PRIMARY KEY(換句話說,如果聯接不能基於關鍵字選擇單個行的話),則使用ref。如果使用的鍵僅僅匹配少量行,該聯接類型是不錯的。

3:加入本地緩存(如果一次性獲取的優惠券先放入map中,那麼下次如果還有就不需要從庫中獲取優惠券。統計發現:10件商品,每件商品發50張優惠券
不加本地緩存效率耗時是7.5s,加入本地緩存後耗時約5.5s,整體性能提升了2s)

這個做法主要是在類裏面定義一個map,第一次訪問數據庫後將數據存在map中,後面再有請求時可以先在map中取,map中沒有的話再訪問數據庫,之後將新訪問的數據存在map中。考慮併發問題,可以使用concurrenthashmap。

這種添加本地緩存比較適用於單服務器部署,在集羣情況下是不太好。另一種做法是使用redis構成分佈式緩存。

    private Map couponMap = new ConcurrentHashMap();
        List<Coupon> coupons = new ArrayList<>();
        if (couponMap.get(key) != null) {
            coupons = (List<Coupon>) couponMap.get(key);
        }
        if (couponMap.get(key) == null) {
            coupons = couponDao.getCouponListByPage(coupon);
            if (CollectionUtils.isNotEmpty(coupons)) {
                couponMap.put(key, coupons);
            }
        }

4:對於發券採用批量更新來替代for循環(由上面的約5.5s性能提升爲大約4.8s)

意思就是執行一次數據庫連接 sql的編譯。避免了每次都重新請求數據庫,每次重新編譯sql。

發佈了49 篇原創文章 · 獲贊 16 · 訪問量 2萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章