国产xxxx99真实实拍_久久不雅视频_高清韩国a级特黄毛片_嗯老师别我我受不了了小说

資訊專欄INFORMATION COLUMN

MongoDB導出場景查詢優化

seal_de / 2540人閱讀

摘要:引言前段時間遇到一個類似導出數據場景,觀察下來發現速度會越來越慢,導出萬數據需要耗費分鐘,從日志觀察發現,耗時也是越來越高。而優化后的方式,平均耗時在之間,總耗時中間包括業務邏輯的耗時。

引言

前段時間遇到一個類似導出數據場景,觀察下來發現速度會越來越慢,導出100萬數據需要耗費40-60分鐘,從日志觀察發現,耗時也是越來越高。

原因

從代碼邏輯上看,這里采取了分批次導出的方式,類似前端的分頁,具體是通過skip+limit的方式實現的,那么采用這種方式會有什么問題呢?我們google一下這兩個接口的文檔:

The?cursor.skip()?method is often expensive because it requires the server to walk from the beginning of the collection or index to get the offset or skip position before beginning to return results. As the offset (e.g.?pageNumber?above) increases,?cursor.skip()?will become slower and more CPU intensive. With larger collections,?cursor.skip()?may become IO bound.

簡單來說,隨著頁數的增長,skip()會變得越來越慢,但是具體就我們這里導出的場景來說,按理說應該沒必要每次都去重復計算,做一些無用功,我的理解應該可以拿到一個指針,慢慢遍歷,簡單google之后,我們發現果然是可以這樣做的。

我們可以在持久層新增一個方法,返回一個cursor專門供上層去遍歷數據,這樣就不用再去遍歷已經導出過的結果集,從O(N2)優化到了O(N),這里還可以指定一個batchSize,設置一次從MongoDB中抓取的數據量(元素個數),注意這里最大是4M.

/**
     * 

Limits the number of elements returned in one batch. A cursor * typically fetches a batch of result objects and store them * locally.

* *

If {@code batchSize} is positive, it represents the size of each batch of objects retrieved. It can be adjusted to optimize * performance and limit data transfer.

* *

If {@code batchSize} is negative, it will limit of number objects returned, that fit within the max batch size limit (usually * 4MB), and cursor will be closed. For example if {@code batchSize} is -10, then the server will return a maximum of 10 documents and * as many as can fit in 4MB, then close the cursor. Note that this feature is different from limit() in that documents must fit within * a maximum size, and it removes the need to send a request to close the cursor server-side.

*/

比如說我這里配置的8000,那么mongo客戶端就會去默認抓取這么多的數據量:

經過本地簡單的測試,我們發現性能已經有了飛躍的提升,導出30萬數據,采用之前的方式,翻頁到后面平均要500ms,總耗時60039ms。而優化后的方式,平均耗時在100ms-200ms之間,總耗時16667ms(中間包括業務邏輯的耗時)。

使用
DBCursor cursor = collection.find(query).batchSize(8000);
while (dbCursor.hasNext()) {
  DBObject nextItem = dbCursor.next();
  //業務代碼
  ... 
  //
}

那么我們再看看hasNext內部的邏輯好嗎?好的.

    @Override
    public boolean hasNext() {
        if (closed) {
            throw new IllegalStateException("Cursor has been closed");
        }

        if (nextBatch != null) {
            return true;
        }

        if (limitReached()) {
            return false;
        }

        while (serverCursor != null) {
            //這里會向mongo發送一條指令去抓取數據
            getMore();
            if (nextBatch != null) {
                return true;
            }
        }

        return false;
    }
    
    
    private void getMore() {
        Connection connection = connectionSource.getConnection();
        try {
            if(serverIsAtLeastVersionThreeDotTwo(connection.getDescription()){
                try {
//可以看到這里其實是調用了`nextBatch`指令        
initFromCommandResult(connection.command(namespace.getDatabaseName(),
                                                             asGetMoreCommandDocument(),
                                                             false,
                                                             new NoOpFieldNameValidator(),
                                                             CommandResultDocumentCodec.create(decoder, "nextBatch")));
                } catch (MongoCommandException e) {
                    throw translateCommandException(e, serverCursor);
                }
            } else {
                initFromQueryResult(connection.getMore(namespace, serverCursor.getId(),
                                                       getNumberToReturn(limit, batchSize, count),
                                                       decoder));
            }
            if (limitReached()) {
                killCursor(connection);
            }
        } finally {
            connection.release();
        }
    }

最后initFromCommandResult 拿到結果并解析成Bson對象

總結

我們平常寫代碼的時候,最好都能夠針對每個方法、接口甚至是更細的粒度加上埋點,也可以設置成debug級別,這樣利用log4j/logback等日志框架動態更新級別,可以隨時查看耗時,從而更能夠針對性的優化,比如Spring有個有個工具類StopWatch就可以做這件事.

對于本文說的這個場景,我們首先看看是不是代碼的邏輯有問題,然后看看是不是數據庫的問題,比如說沒建索引、數據量過大等,再去想辦法針對性的優化,而不要上來就擼代碼。

文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。

轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/19036.html

相關文章

  • Web優化躬行記(5)——網站優化

    摘要:最近閱讀了很多優秀的網站性能優化的文章,所以自己也想總結一些最近優化的手段和方法。個人感覺性能優化的核心是減少延遲,加速展現。初步以為是這個功能導致的服務掛起,詢問相關操作人員,得到當時的操作過程。  最近閱讀了很多優秀的網站性能優化的文章,所以自己也想總結一些最近優化的手段和方法。   個人感覺性能優化的核心是:減少延遲,加速展現。   本文主要從產品設計、前端、后端和網絡四個...

    233jl 評論0 收藏0
  • 記一次MongoDB高負載的性能優化

    摘要:年月日本文是關于記錄某次游戲服務端的性能優化此處涉及的技術包括引擎隨著游戲導入人數逐漸增加單個集合的文檔數已經超過經常有玩家反饋說卡特別是在服務器遷移后從核降到核卡頓更嚴重了遂開始排查問題確認服務器壓力首先使用命令查看總體情況此時占用不高 Last-Modified: 2019年6月13日11:08:19 本文是關于記錄某次游戲服務端的性能優化, 此處涉及的技術包括: MongoDB...

    huhud 評論0 收藏0
  • 記一次MongoDB高負載的性能優化

    摘要:年月日本文是關于記錄某次游戲服務端的性能優化此處涉及的技術包括引擎隨著游戲導入人數逐漸增加單個集合的文檔數已經超過經常有玩家反饋說卡特別是在服務器遷移后從核降到核卡頓更嚴重了遂開始排查問題確認服務器壓力首先使用命令查看總體情況此時占用不高 Last-Modified: 2019年6月13日11:08:19 本文是關于記錄某次游戲服務端的性能優化, 此處涉及的技術包括: MongoDB...

    vibiu 評論0 收藏0

發表評論

0條評論

最新活動
閱讀需要支付1元查看
<