在相同業(ye)務場(chang)景(jing)下(xia),架構(gou)設計(ji)和庫、集(ji)合、索引等設計(ji)會影響查(cha)詢(xun)性能,良好的(de)設計(ji)可(ke)以提高(gao)查(cha)詢(xun)性能,反之(zhi)會出現很多慢請(qing)求(執行時間很長的(de)語(yu)句),這些慢請(qing)求會消耗很多的(de)系統性能。
排查思路
DDS支持在控制臺(tai)上查看(kan)慢(man)日志(zhi)信息,針對慢(man)日志(zhi)中過長的(de)(de)操(cao)(cao)作(zuo)需要從執(zhi)行(xing)最慢(man)的(de)(de)操(cao)(cao)作(zuo)入手,逐(zhu)個進行(xing)優化。
- 對于操作執行時長超過1s時,對應的操作可能會有問題,需要視具體情況分析。
- 對于操作執行時長超過10s時,則需要優化對應的操作。
說明若存(cun)在某個聚(ju)合(he)操(cao)作,因其(qi)比較慢,此時操(cao)作執(zhi)行時長超過10s的情況屬于正(zheng)常現象(xiang)。
分析方法
步(bu)驟(zou) 1 連(lian)接數據庫。
步驟 2 針對(dui)慢查詢可以通過如下命令檢查其(qi)執行(xing)計劃。
explain()
例如:
db.test.find({"data_id" : "ae4b5769-896f-465c-9fbd-3fd2f3357637"}).explain();
db.test.find({"data_id" : "775f57c2-b63e-45d7-b581-3822dba231b4"}).explain("executionStats");
對于查詢而言,因為覆蓋查詢不需要讀取文檔,而是直接從索引中返回結果,這樣的查詢非常高效,所以 盡可能使用索引覆蓋查詢 。如果explain()的輸出顯(xian)示indexOnly字段(duan)為真,則說明這個查詢就(jiu)被一個索引(yin)覆蓋(gai)。
步驟 3 執行計劃解(jie)析(xi)。
- 查看執行時間。
executionStats.executionStages.executionTimeMillisEstimate和executionStats.executionStages.inputStage. executionTimeMillisEstimate時間越(yue)短越(yue)好(hao)。
參數說明
| 參數名稱 | 描述 |
|---|---|
| executionStats.executionTimeMillis | 執行計劃選擇和執行的所有時間 |
| executionStats.executionStages.executionTimeMillisEstimate | 最優執行計劃的執行完成時間 |
| executionStats.executionStages.inputStage. executionTimeMillisEstimate | 最優執行計劃下的子階段執行完成時間 |
- 查看掃描條數。
如(ru)下(xia)表中三個條目相同為最(zui)佳。
參數說明
| 參數名稱 | 描述 |
|---|---|
| executionStats. nReturned | 匹配查詢條件的文檔數 |
| executionStats .totalKeysExamined | 索引掃描條目數 |
| executionStats .totalDocsExamined | 文檔掃描條目數 |
- 查看Stage狀態。
性能(neng)較好的Stage狀態組(zu)合如下(xia):
- Fetch+IDHACK
- Fetch+ixscan,
- Limit+(Fetch+ixscan)
- PROJECTION+ixscan
狀態說明
| 狀態名稱 | 描述 |
|---|---|
| COLLSCAN | 全表掃描 |
| SORT | 內存中進行排序 |
| IDHACK | 根據_id進行查詢 |
| TEXT | 全文索引 |
| COUNTSCAN | 未用索引計數 |
| FETCH | 索引掃描 |
| LIMIT | 使用Limit限制返回數 |
| SUBPLA | 未用索引的$or查詢階段 |
| PROJECTION | 使用索引計數 |
| COUNT_SCAN | 使用索引計數 |
優化方案
- 對于無索引覆蓋的查詢,則需要根據查詢條件創建對應索引。
- 對于點查可以創建hash索引。
- 對于多字段查詢,單字段重復度較高的場景,創建復合索引。
- 對于范圍查找,結果集有序的查詢,創建升序或者降序索引。
- 對于復合索引,由于復合索引是前綴排序查詢,所以查詢條件的順序要與索引字段的順序一致。
- 對于分區集合(表)、大集合(超過10萬記錄),不要直接對大數據量的表使用模糊查詢(即不能使用like)。這樣會造成查詢掃描的記錄過多,建議先基于索引字段查詢,過濾出較小的數據集后再使用模糊查詢。
- 避免使用not。MongoDB 并不會對缺失的數據進行索引,因此not的查詢條件將會要求在一個結果集中掃描所有記錄。如果$not是唯一的查詢條件,會對集合進行全表掃描。
- 用and時把匹配最少結果的條件放在最前面,用or時把匹配最多結果的條件放在最前面。
- 檢查實例規格的性能基線,分析當前的業務需求是否達到上限,如已達當前實例性能瓶頸,請及時提升實例規格。