成人免费xxxxx在线视频软件_久久精品久久久_亚洲国产精品久久久_天天色天天色_亚洲人成一区_欧美一级欧美三级在线观看

震撼揭秘:線上MongoDB慢查詢終極優(yōu)化實(shí)戰(zhàn)解析

數(shù)據(jù)庫(kù) 其他數(shù)據(jù)庫(kù)
選擇合適的分片鍵是MongoDB分片設(shè)計(jì)中的重要步驟。分片鍵的選擇需要考慮數(shù)據(jù)的分布、查詢模式和寫操作分布等因素。理解分片鍵的約束和注意事項(xiàng),可以幫助我們?cè)O(shè)計(jì)高效、可擴(kuò)展的分布式數(shù)據(jù)庫(kù)架構(gòu)。

背景

研發(fā)反饋指出,線上某個(gè)頁(yè)面的響應(yīng)速度異常緩慢,達(dá)到了16秒,嚴(yán)重影響了業(yè)務(wù)的正常運(yùn)行。經(jīng)過與研發(fā)的溝通得知,該頁(yè)面調(diào)用的數(shù)據(jù)集合只會(huì)保留7天的數(shù)據(jù),集合有6000萬(wàn)條記錄。針對(duì)過期數(shù)據(jù)的處理,使用了根據(jù) create_time 字段創(chuàng)建的過期索引,以自動(dòng)使數(shù)據(jù)失效。此外,數(shù)據(jù)集合還通過 company_id 字段進(jìn)行了哈希分片。

問題排查

慢語(yǔ)句分析

在后臺(tái)拿到了慢查詢語(yǔ)句,如下:

db.visitor.find({
"company_id": 13272,
"create_time": {
"$gte": ISODate("2024-04-11T00:00:00.000+0800"),
"$lte": ISODate("2024-04-11T23:59:59.000+0800")
}
});


db.visitor.find({
"company_id": 13272,
"create_time": {
"$gte": ISODate("2024-04-12T00:00:00.000+0800"),
"$lte": ISODate("2024-04-18T23:59:59.000+0800")
}
});

很簡(jiǎn)單的一個(gè)查詢,語(yǔ)句上沒有再優(yōu)化的必要了,如果索引都在不應(yīng)該出現(xiàn)這種十多秒的耗時(shí),接下來(lái)開始分析索引。

索引分析

索引如下:
db.getCollection("visitor").createIndex({
"company_id": "hashed"
}, {
name: "company_id_hashed"
});
db.getCollection("visitor").createIndex({
"company_id": NumberInt("1")
}, {
name: "company_id_1"
});
db.getCollection("visitor").createIndex({
"create_time": NumberInt("1")
}, {
name: "create_time_1",
expireAfterSeconds: NumberInt("604800")
});
  • company_id_hashed:創(chuàng)建集合分片使用的hash索引
  • company_id_1:普通查詢的索引
  • create_time_1:過期時(shí)間的索引

根據(jù)研發(fā)團(tuán)隊(duì)的反饋和對(duì)數(shù)據(jù)的分析,我們發(fā)現(xiàn)當(dāng)前集合使用 company_id_hashed 索引進(jìn)行分片存在問題。哈希索引對(duì)等值查詢最為友好,但對(duì)于范圍查詢支持不佳。由于 company_id 是公司維度字段,相同數(shù)據(jù)較多,因此使用哈希分片并不合適。建議直接創(chuàng)建 company_id 和 create_time 的聯(lián)合范圍分片鍵。這樣不僅能夠友好地支持范圍查詢,還能更細(xì)粒度地拆分?jǐn)?shù)據(jù),提高查詢和寫入的效率。

針對(duì)當(dāng)前情況就這點(diǎn)數(shù)據(jù)量,按理說(shuō)會(huì)用到索引的,不應(yīng)該執(zhí)行耗時(shí)16s,接下來(lái)執(zhí)行計(jì)劃分析。

Explain執(zhí)行計(jì)劃

winningPlan

"inputStage": {
                            "stage": "FETCH",
                            "filter": {
                                "$and": [
                                    {
                                        "company_id": {
                                            "$eq": 13272
                                        }
                                    },
                                    {
                                        "create_time": {
                                            "$lte": ISODate("2024-04-17T15:59:59.000Z")
                                        }
                                    },
                                    {
                                        "create_time": {
                                            "$gte": ISODate("2024-04-10T16:00:00.000Z")
                                        }
                                    }
                                ]
                            },
                            "inputStage": {
                                "stage": "IXSCAN",
                                "keyPattern": {
                                    "company_id": "hashed"
                                },
                                "indexName": "company_id_hashed",
                                "isMultiKey": false,
                                "isUnique": false,
                                "isSparse": false,
                                "isPartial": false,
                                "indexVersion": NumberInt("2"),
                                "direction": "forward",
                                "indexBounds": {
                                    "company_id": [
                                        "[7977521071453068053, 7977521071453068053]"

這部分顯示只用到了company_id_hashed索引,沒有用到create_time_1索引。

rejectedPlans
"stage": "SHARDING_FILTER",
"inputStage": {
"stage": "FETCH",
"filter": {
"company_id": {
"$eq": 13272
}
},
"inputStage": {
"stage": "IXSCAN",
"keyPattern": {
"create_time": 1
},
"indexName": "create_time_1",
"isMultiKey": false,
"multiKeyPaths": {
"create_time": [ ]
},
"isUnique": false,
"isSparse": false,
"isPartial": false,
"indexVersion": NumberInt("2"),
"direction": "forward",
"indexBounds": {
"create_time": [
"[new Date(1712764800000), new Date(1713369599000)]"
]
}
}
}
},
{
"stage": "SHARDING_FILTER",
"inputStage": {
"stage": "FETCH",
"filter": {
"$and": [
{
"create_time": {
"$lte": ISODate("2024-04-17T15:59:59.000Z")
}
},
{
"create_time": {
"$gte": ISODate("2024-04-10T16:00:00.000Z")
}
}
]
},
"inputStage": {
"stage": "IXSCAN",
"keyPattern": {
"company_id": 1
},
"indexName": "company_id_1",
"isMultiKey": false,
"multiKeyPaths": {
"company_id": [ ]
},

這部分顯示的是被拒絕的執(zhí)行計(jì)劃列表,不會(huì)用到company_id_1、create_time_1索引

executionStats
"nReturned": NumberInt("229707"),
"executionTimeMillis": NumberInt("15668"),
"totalKeysExamined": NumberInt("238012"),
"totalDocsExamined": NumberInt("238012"),
"executionStages": {
"stage": "SINGLE_SHARD",
"nReturned": NumberInt("229707"),
"executionTimeMillis": NumberInt("15668"),
"totalKeysExamined": NumberInt("238012"),
"totalDocsExamined": NumberInt("238012"),
"totalChildMillis": NumberLong("15667"),
"shards": [
{
"shardName": "d-m5eee03fdeaeaee4",
"executionSuccess": true,
"executionStages": {
"stage": "SHARDING_FILTER",
"nReturned": NumberInt("229707"),
"executionTimeMillisEstimate": NumberInt("14996"),
"works": NumberInt("238013"),
"advanced": NumberInt("229707"),
"needTime": NumberInt("8305"),
"needYield": NumberInt("0"),
"saveState": NumberInt("1980"),
"restoreState": NumberInt("1980"),
"isEOF": NumberInt("1"),
"chunkSkips": NumberInt("0"),
"inputStage": {
"stage": "FETCH",
"filter": {
"$and": [
{
"company_id": {
"$eq": 13272
}
},
{
"create_time": {
"$lte": ISODate("2024-04-17T15:59:59.000Z")
}
},
{
"create_time": {
"$gte": ISODate("2024-04-10T16:00:00.000Z")
}
}
]
},
"nReturned": NumberInt("229707"),
"executionTimeMillisEstimate": NumberInt("14595"),
"works": NumberInt("238013"),
"advanced": NumberInt("229707"),
"needTime": NumberInt("8305"),
"needYield": NumberInt("0"),
"saveState": NumberInt("1980"),
"restoreState": NumberInt("1980"),
"isEOF": NumberInt("1"),
"docsExamined": NumberInt("238012"),
"alreadyHasObj": NumberInt("0"),
"inputStage": {
"stage": "IXSCAN",
"nReturned": NumberInt("238012"),
"executionTimeMillisEstimate": NumberInt("251"),
"works": NumberInt("238013"),
"advanced": NumberInt("238012"),
"needTime": NumberInt("0"),
"needYield": NumberInt("0"),
"saveState": NumberInt("1980"),
"restoreState": NumberInt("1980"),
"isEOF": NumberInt("1"),
"keyPattern": {
"company_id": "hashed"
},
"indexName": "company_id_hashed",
"isMultiKey": false,
"isUnique": false,
"isSparse": false,
"isPartial": false,
"indexVersion": NumberInt("2"),
"direction": "forward",
"indexBounds": {
"company_id": [
"[7977521071453068053, 7977521071453068053]"
]
},
"keysExamined": NumberInt("238012"),
"seeks": NumberInt("1"),
"dupsTested": NumberInt("0"),
"dupsDropped": NumberInt("0")

這部分顯示的是查詢的執(zhí)行統(tǒng)計(jì)信息。

索引分析

通過explain的執(zhí)行計(jì)劃,可以看到索引的使用上存在問題,按理說(shuō)company_id、create_time都已創(chuàng)建索引,為什么沒有使用上?是什么使它失效,沒有用上create_time索引?

下面列舉了失效的情況:

  • 索引選擇性不高:由于查詢條件是一個(gè)范圍查詢,create_time 字段可能有許多不同的值滿足條件。因此,單鍵索引 create_time_1 的選擇性(即索引中不同值的比例)可能不高,這使得使用該索引無(wú)法有效地減少需要檢索的文檔數(shù)量。
  • 查詢需要跨越多個(gè)索引鍵值:查詢涉及到了兩個(gè)字段 company_id 和 create_time。雖然索引 create_time_1 可以幫助過濾 create_time 符合條件的文檔,但在執(zhí)行查詢時(shí),還需要考慮 company_id 的匹配條件。因此,MongoDB 需要在兩個(gè)索引之間進(jìn)行查找和合并,而不是簡(jiǎn)單地使用單個(gè)索引來(lái)解決查詢。
  • 額外的查找和合并成本:在涉及多個(gè)條件的查詢中,MongoDB 會(huì)嘗試使用覆蓋索引(Covered Index)來(lái)盡可能地減少在磁盤上的文檔檢索。然而,在這種情況下,create_time_1 索引不能單獨(dú)滿足查詢條件,因此 MongoDB 還需要查找和合并從 company_id_1 索引中過濾出來(lái)的文檔。這種額外的查找和合并過程會(huì)增加查詢的成本,并且降低性能。

問題原因

首先,集合片鍵選擇錯(cuò)誤是問題的根本原因。由于集合的分片鍵是 company_id_hashed,查詢必然會(huì)使用這個(gè)索引。然而,這引發(fā)了一系列連鎖反應(yīng):即“查詢需要跨越多個(gè)索引鍵值”和“額外的查找和合并成本”。

具體來(lái)說(shuō),由于需要進(jìn)行范圍查詢,首先會(huì)使用 company_id_hashed 索引。然而,MongoDB 還需要查找和合并從 company_id_1 索引中過濾出來(lái)的文檔。這種額外的查找和合并過程會(huì)增加查詢的成本,并且降低性能。這也導(dǎo)致了 create_time_1 索引無(wú)法被有效利用。

針對(duì)此問題,我們將已有索引進(jìn)行了整改,如下:

分片鍵不重做(達(dá)到毫秒級(jí)別)

//分片鍵不做修整
db.getCollection("visitor").createIndex({
"company_id": "hashed"
}, {
name: "company_id_hashed"
});


//添加范圍聯(lián)合索引
db.getCollection("js_visitor").createIndex({
    "company_id": NumberInt("1"),
    "create_time": NumberInt("1")
}, {
    name: "company_id_create_time"
});


//過期索引保留
db.getCollection("visitor").createIndex({
"create_time": NumberInt("1")
}, {
name: "create_time_1",
expireAfterSeconds: NumberInt("604800")
});


//刪掉company_id
db.getCollection("visitor").createIndex({
"company_id": NumberInt("1")
}, {
name: "company_id_1"
});

分片鍵重做(最完美方案,但需要重新創(chuàng)建集合并遷移數(shù)據(jù))

//分片鍵重做
sh.shardCollection("cmdb.visitor",{ "company_id": "1","create_time": "1"});


索引如下:
db.getCollection("js_visitor").createIndex({
    "company_id": NumberInt("1"),
    "create_time": NumberInt("1")
}, {
    name: "company_id_create_time"
});


//過期索引保留
db.getCollection("visitor").createIndex({
"create_time": NumberInt("1")
}, {
name: "create_time_1",
expireAfterSeconds: NumberInt("604800")
});

注意事項(xiàng)

1、選擇合適的分片鍵

  • 分片鍵應(yīng)盡量均勻分布,以避免“熱點(diǎn)”問題(即大多數(shù)查詢集中在某些特定分片上,導(dǎo)致這些分片負(fù)載過重)。
  • 常用的選擇包括用戶ID、時(shí)間戳等具有自然分布特性的字段。

2、查詢模式

  • 考慮主要的查詢模式,選擇的分片鍵應(yīng)當(dāng)能夠最大化地利用分片查詢。例如,如果大部分查詢都是基于用戶ID的,那么用戶ID就是一個(gè)合適的分片鍵。

3、寫操作分布

  • 分片鍵應(yīng)盡量避免集中寫入。例如,使用時(shí)間戳作為分片鍵可能導(dǎo)致最新的分片上寫入壓力過大。

4、更改分片鍵

  • 分片鍵在集合創(chuàng)建后無(wú)法更改,因此在設(shè)計(jì)時(shí)需要慎重選擇。如果需要更改分片鍵,通常需要重新創(chuàng)建集合并遷移數(shù)據(jù)。

5、復(fù)合分片鍵

  • 可以使用多個(gè)字段組合成復(fù)合分片鍵,以滿足更復(fù)雜的查詢需求。例如,使用 { userId: 1, timestamp: 1 } 作為分片鍵,可以優(yōu)化基于用戶ID和時(shí)間戳的查詢。

6、哈希分片鍵

  • 哈希分片鍵可以將數(shù)據(jù)均勻地分布到所有分片中,適合高并發(fā)的寫入場(chǎng)景。例如,使用 { _id: "hashed" } 作為分片鍵。

總結(jié)

選擇合適的分片鍵是MongoDB分片設(shè)計(jì)中的重要步驟。分片鍵的選擇需要考慮數(shù)據(jù)的分布、查詢模式和寫操作分布等因素。理解分片鍵的約束和注意事項(xiàng),可以幫助我們?cè)O(shè)計(jì)高效、可擴(kuò)展的分布式數(shù)據(jù)庫(kù)架構(gòu)。

責(zé)任編輯:武曉燕 來(lái)源: DBA實(shí)戰(zhàn)
相關(guān)推薦

2024-04-29 08:00:00

MongoDB索引

2023-12-11 06:27:39

MySQL線上業(yè)務(wù)優(yōu)化后臺(tái)上傳文件

2022-11-16 08:00:37

MongoDB阿里云的登錄

2023-12-08 13:23:00

大數(shù)據(jù)MySQL存儲(chǔ)

2022-04-22 14:41:12

美團(tuán)慢查詢數(shù)據(jù)庫(kù)

2024-11-28 19:03:56

2012-12-11 09:48:55

廣域網(wǎng)網(wǎng)絡(luò)優(yōu)化網(wǎng)絡(luò)加速

2012-09-20 10:13:04

MongoDB

2011-04-02 16:45:58

SQL Server查詢優(yōu)化

2017-07-11 15:50:11

前端webpack2優(yōu)化

2011-05-16 17:36:05

SEO

2017-05-23 16:26:26

MySQL優(yōu)化處理

2012-10-08 11:18:05

JavaMVC項(xiàng)目

2020-08-28 08:55:32

商城系統(tǒng)高并發(fā)

2025-06-25 09:30:14

2025-01-15 12:48:30

2011-07-07 14:15:35

WIFI無(wú)線

2017-08-18 22:40:33

線上線程備份

2025-05-12 04:01:00

2023-09-01 15:34:34

數(shù)據(jù)庫(kù)開發(fā)
點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號(hào)

主站蜘蛛池模板: 欧美精品三区 | 成人在线一区二区 | 亚洲福利视频一区二区 | www久久国产| 日本精品一区二区三区视频 | 免费三级网| 懂色av一区二区三区在线播放 | 国产精品爱久久久久久久 | 亚洲精品日韩一区二区电影 | 又爽又黄axxx片免费观看 | 欧美成人在线免费 | 国产亚洲网站 | 精品精品 | 亚洲欧美一区二区三区视频 | 午夜电影在线播放 | 日韩欧美在线免费观看 | av一级在线观看 | 日韩免费视频一区二区 | 国产日韩一区二区 | 欧美在线视频一区 | 日日夜精品视频 | 亚洲视频中文 | 国产精品久久九九 | 色视频网站 | 久久国产精品久久久久久久久久 | 99精品欧美一区二区三区综合在线 | 日本精品久久久久久久 | 成人在线看片 | 伊人欧美视频 | 国产91在线视频 | 国产一区二区三区久久久久久久久 | 欧美中文字幕在线观看 | 日本免费视频 | 99re在线视频 | 毛片一级片| 亚洲一区二区在线电影 | 国产在线观 | 在线欧美一区二区 | 午夜精品久久久久久久久久久久久 | 九九久久精品 | 亚洲二区在线 |