日本熟妇hd丰满老熟妇,中文字幕一区二区三区在线不卡 ,亚洲成片在线观看,免费女同在线一区二区

云數據庫查詢優化

EMAS Serverless云數據庫使用的是MongoDB。在數據量比較大的情況下,有時候查詢操作會報錯operation exceeded time limit。本文介紹如何進行查詢優化以避免此類問題。

設置合適的索引

如果您的查詢操作包含了過濾條件(包含等值測試和范圍過濾)或者是排序功能,則要考慮給集合添加索引。

說明

在創建索引時,可以去掉那些沒有選擇性的等值測試字段或范圍過濾字段,以減少索引空間的占用。

針對復雜的查詢語句,包含了等值測試、范圍過濾以及排序功能,這里提供一個建立索引的方法。

    • 索引中字段的順序需要按照等值測試字段、排序字段、范圍過濾字段的方式排列。

    • 若等值測試包含多個字段,它們之間的順序可以任意互換,索引中的升序降序也不影響。

    • 若排序字段包含多個字段,添加到索引中順序需要按照排序中的順序,升序降序也要一致。

    • 若范圍過濾包含多個字段,則優先將基數值(集合中字段不同值的數量)少的字段放到前面。

說明

如果您的集合上有多條索引,尤其是您的查詢語句較復雜時,MongoDB不一定能為您選擇正確的索引,建議您在查詢語句中指定此次查詢過程中使用的索引。

如下所示,您可以創建一個復合索引,依次包含coursesex, class, name, birthmonth, scorecoursesex屬于等值測試字段,它們需要放在最前面,順序也可以互換。birthmonthscore屬于范圍過濾字段,需要放到最后,由于birthmonth取值范圍是1-12,score的取值范圍是0-100,所以需要把birthmonth放到score前面。classname屬于排序字段,應該放在中間,順序和升降序都和排序時一致。

//在分數表中,查詢數學成績大于80分并且下半年出生的男生的記錄,并且按照班級和姓名排序。
mpserverless.db.collection('score').find(
  {
    course: "Math",
    sex: "male",
    birthmonth: { $gt: 6 },
    score: { $gt: 80 },
  },
  {
    sort: { class: 1, name: 1 },
  },
);

大量數據查詢優化

如果您的數據量非常大,在設置合適的索引之后仍然會查詢超時,您要考慮以下優化方案。

  • 盡量避免使用skip,至少不應該skip比較大的值,因為skip操作MongoDB服務端依然會掃描被skip的數據,帶skip操作的耗時和skip的數量線性相關。您可以考慮使用排序和范圍查詢功能來替代直接使用skip。

  • 對于非常大的數據可以分段來查詢,即通過一定的條件將一次查詢拆分為多次查詢操作。

分段計算count

您可以通過findOne+RangeQuery+Skip+Sort的方式來分段計算Count,注意使用該方法需要添加合適的索引。

如下面的代碼示例所示,以_id作為分段列,我們先調用findOne接口,依次查詢第100001,200001,300001....個_id值,當剩余數據條數不足100001條時,findOne返回的result為空,這時可以通過count獲取剩余的記錄數。注意在調用findOne時需要指定查詢條件_id大于等于特定值,需要指定排序規則為按_id升序排列,需要指定查詢跳過100000條記錄;在調用count查詢時需要指定_id值大于最后一次findOne返回的_id。

module.exports = async (ctx) => {
    const skip = 100000;
    let count = 0;
    let minId = { $minKey: 1 };
    const collection = ctx.mpserverless.db.collection('collectionName');
    while (true) {
        const query = { _id: { $gte: minId } };
        const options = {
            skip,
            projection: { _id: 1 },
            sort: { _id: 1 },
        };
        const findOneResult = await collection.findOne(query, options);
        const { affectedDocs, success } = findOneResult;
        if (!success) {
            throw new Error("findOne return success false");
        }
        if (affectedDocs > 0) {
            const newId = findOneResult.result._id;
            minId = newId;
            count += skip;
        } else {
            break;
        }
    }
    const query = { _id: { $gte: minId } };
    const countResult = await collection.count(query);
    const { affectedDocs, success } = countResult;
    if (!success) {
        throw new Error("count return success false");
    }
    count += affectedDocs;
    return count;
};

遍歷整個集合

您應該避免使用find+Skip+Limit的查詢方式來遍歷整個集合,因為這種方式隨著Skip數量的增長響應時間會越來越慢,還可能會造成請求超時。您可以改為使用find+RangeQuery+Limit+Sort的方式。

下面的代碼給出了一個示例。將數據按_id排列,每次查詢時都指定查詢條件大于上次查詢結果中的最后一條記錄的_id,依次遍歷到最后。

module.exports = async (ctx) => {
    const pageSize = 100;
    let minId = { $minKey: 1 };
    const collection = ctx.mpserverless.db.collection('collectionName');
    while (true) {
        const query = { _id: { $gt: minId } };
        const options = {
            limit: pageSize,
            sort: { _id: 1 },
        };
        const findResult = await collection.find(query, options);
        const { affectedDocs, success } = findResult;
        if (!success) {
            throw new Error("find return success false");
        }
        if (affectedDocs > 0) {
            const data = findResult.result;
            const lastDoc = data[data.length -1];
            minId = lastDoc._id;
            //todo 在這里添加處理data列表的邏輯。
        } else {
            break;
        }
    }
    return 'success';
};

分頁查詢優化

您應該使用上一頁、下一頁、上n頁(其中n是一個比較小的數字)、下n頁的翻頁功能來替換隨機翻頁。您可以參考百度或者谷歌的搜索結果的分頁功能,當結果頁數非常多時,不展示共有多少頁,僅支持在前10頁中支持隨機翻頁;再往下翻頁的過程中,不再支持隨機翻頁,僅支持向下翻一個較小的頁數,這樣就可以在已經查詢出結果的基礎上再使用find+RangeQuery+Skip(少量)+Limit+Sort的方式來快速查詢到結果。例如當您已經查詢出第13頁的數據后,再次查詢第17頁的數據時,就可以把第13頁的最后一條數據作為RangeQuery的判斷條件,跳過3頁的數據行數,再查詢一頁的數據就是第17頁的數據。