@mongodb-js/explain-plan-helper 1.5.18 → 1.6.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.d.ts +6 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +29 -11
- package/dist/utils.d.ts +1 -1
- package/dist/utils.d.ts.map +1 -1
- package/dist/utils.js +4 -4
- package/package.json +6 -6
package/dist/index.d.ts
CHANGED
|
@@ -16,6 +16,9 @@ export type IndexInformation = {
|
|
|
16
16
|
shard: null;
|
|
17
17
|
index: string;
|
|
18
18
|
});
|
|
19
|
+
export type SerializedExplainPlan = Pick<ExplainPlan, 'namespace' | 'parsedQuery' | 'executionSuccess' | 'nReturned' | 'executionTimeMillis' | 'totalKeysExamined' | 'totalDocsExamined' | 'originalExplainData' | 'executionStats' | 'isCovered' | 'isMultiKey' | 'inMemorySort' | 'isCollectionScan' | 'isSharded' | 'numShards' | 'indexType'> & {
|
|
20
|
+
usedIndexes: IndexInformation[];
|
|
21
|
+
};
|
|
19
22
|
export declare class ExplainPlan {
|
|
20
23
|
namespace: string;
|
|
21
24
|
parsedQuery: Stage;
|
|
@@ -28,7 +31,8 @@ export declare class ExplainPlan {
|
|
|
28
31
|
executionStats?: ExecutionStats;
|
|
29
32
|
winningPlan: Stage;
|
|
30
33
|
constructor(originalExplainData: Stage);
|
|
31
|
-
|
|
34
|
+
private _getIndexEntries;
|
|
35
|
+
getUsedIndexes(): Promise<IndexInformation[]>;
|
|
32
36
|
get isCovered(): boolean;
|
|
33
37
|
get isMultiKey(): boolean;
|
|
34
38
|
get inMemorySort(): boolean;
|
|
@@ -62,7 +66,7 @@ export declare class ExplainPlan {
|
|
|
62
66
|
findAllStagesByName(name: string, root?: Stage): Stage[];
|
|
63
67
|
/** DFS stack iterator implementation */
|
|
64
68
|
_getStageIterator(root?: Stage): Iterable<Stage>;
|
|
65
|
-
serialize():
|
|
69
|
+
serialize(): Promise<SerializedExplainPlan>;
|
|
66
70
|
/**
|
|
67
71
|
* Returns child stage or stages of current stage as array. If there are
|
|
68
72
|
* no more child stages, returns empty array []. Also works for sharded
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAC;AAG5D,QAAA,MAAM,OAAO,eAAgC,CAAC;AAE9C,MAAM,MAAM,KAAK,GAAG,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,GAAG;IACxC,KAAK,EAAE,MAAM,CAAC;IACd,CAAC,OAAO,CAAC,EAAE,KAAK,GAAG,IAAI,CAAC;CACzB,CAAC;AACF,MAAM,MAAM,gBAAgB,GAAG;IAAE,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;CAAE,GAAG,CACjE;IAAE,KAAK,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,GAChC;IAAE,KAAK,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,IAAI,CAAA;CAAE,GAC9B;IAAE,KAAK,EAAE,IAAI,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,CACjC,CAAC;
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAC;AAG5D,QAAA,MAAM,OAAO,eAAgC,CAAC;AAE9C,MAAM,MAAM,KAAK,GAAG,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,GAAG;IACxC,KAAK,EAAE,MAAM,CAAC;IACd,CAAC,OAAO,CAAC,EAAE,KAAK,GAAG,IAAI,CAAC;CACzB,CAAC;AACF,MAAM,MAAM,gBAAgB,GAAG;IAAE,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;CAAE,GAAG,CACjE;IAAE,KAAK,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,GAChC;IAAE,KAAK,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,IAAI,CAAA;CAAE,GAC9B;IAAE,KAAK,EAAE,IAAI,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,CACjC,CAAC;AAWF,MAAM,MAAM,qBAAqB,GAAG,IAAI,CACtC,WAAW,EACT,WAAW,GACX,aAAa,GACb,kBAAkB,GAClB,WAAW,GACX,qBAAqB,GACrB,mBAAmB,GACnB,mBAAmB,GACnB,qBAAqB,GACrB,gBAAgB,GAChB,WAAW,GACX,YAAY,GACZ,cAAc,GACd,kBAAkB,GAClB,WAAW,GACX,WAAW,GACX,WAAW,CACd,GAAG;IAAE,WAAW,EAAE,gBAAgB,EAAE,CAAA;CAAE,CAAC;AAExC,qBAAa,WAAW;IACtB,SAAS,EAAE,MAAM,CAAC;IAClB,WAAW,EAAE,KAAK,CAAC;IACnB,gBAAgB,EAAE,OAAO,CAAC;IAC1B,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;IACzB,mBAAmB,EAAE,MAAM,GAAG,IAAI,CAAC;IACnC,iBAAiB,EAAE,MAAM,GAAG,IAAI,CAAC;IACjC,iBAAiB,EAAE,MAAM,GAAG,IAAI,CAAC;IACjC,mBAAmB,EAAE,KAAK,CAAC;IAC3B,cAAc,CAAC,EAAE,cAAc,CAAC;IAChC,WAAW,EAAE,KAAK,CAAC;gBAEP,mBAAmB,EAAE,KAAK;IAqBtC,OAAO,CAAC,gBAAgB;IA4ClB,cAAc,IAAI,OAAO,CAAC,gBAAgB,EAAE,CAAC;IAenD,IAAI,SAAS,IAAI,OAAO,CASvB;IAED,IAAI,UAAU,IAAI,OAAO,CAExB;IAED,IAAI,YAAY,IAAI,OAAO,CAE1B;IAED,IAAI,gBAAgB,IAAI,OAAO,CAE9B;IAED,IAAI,SAAS,IAAI,OAAO,CAEvB;IAED,IAAI,SAAS,IAAI,MAAM,CAItB;IAED,IAAI,eAAe,IAAI,OAAO,CAK7B;IAED,IAAI,SAAS,gFAkDZ;IAED;;;;;;;;;;OAUG;IACH,eAAe,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,KAAK,GAAG,KAAK,GAAG,IAAI;IASzD;;;;;;;;;OASG;IACH,mBAAmB,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,KAAK,GAAG,KAAK,EAAE;IAMxD,wCAAwC;IACvC,iBAAiB,CAAC,IAAI,CAAC,EAAE,KAAK,GAAG,QAAQ,CAAC,KAAK,CAAC;IAc3C,SAAS,IAAI,OAAO,CAAC,qBAAqB,CAAC;IAyBjD;;;;;;;OAOG;IACH,MAAM,CAAE,cAAc,CAAC,KAAK,CAAC,EAAE,KAAK,GAAG,QAAQ,CAAC,KAAK,CAAC;IA+BtD;;;;OAIG;IACH,MAAM,CAAC,eAAe,CAAC,KAAK,EAAE,KAAK,GAAG,IAAI;IAQ1C;;;;OAIG;IACH,MAAM,CAAE,eAAe,CAAC,KAAK,EAAE,KAAK,GAAG,QAAQ,CAAC,KAAK,CAAC;CAMvD"}
|
package/dist/index.js
CHANGED
|
@@ -39,13 +39,16 @@ class ExplainPlan {
|
|
|
39
39
|
this.originalExplainData = originalExplainData;
|
|
40
40
|
this.winningPlan = qpInfo.winningPlan;
|
|
41
41
|
}
|
|
42
|
-
|
|
42
|
+
_getIndexEntries() {
|
|
43
43
|
const ixscan = this.findAllStagesByName('IXSCAN');
|
|
44
44
|
const expressIxscan = this.findAllStagesByName('EXPRESS_IXSCAN');
|
|
45
45
|
const countScan = this.findAllStagesByName('COUNT_SCAN');
|
|
46
46
|
// special case for IDHACK stage, using the _id_ index.
|
|
47
47
|
const idhack = this.findStageByName('IDHACK');
|
|
48
|
-
const ret = this.executionStats?.stageIndexes ?? []
|
|
48
|
+
const ret = (this.executionStats?.stageIndexes ?? []).map((indexInfo) => ({
|
|
49
|
+
...indexInfo,
|
|
50
|
+
stage: null,
|
|
51
|
+
}));
|
|
49
52
|
for (const stage of [...ixscan, ...expressIxscan, ...countScan, idhack]) {
|
|
50
53
|
if (!stage)
|
|
51
54
|
continue;
|
|
@@ -58,18 +61,32 @@ class ExplainPlan {
|
|
|
58
61
|
}
|
|
59
62
|
}
|
|
60
63
|
}
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
+
ret.push(stage === idhack
|
|
65
|
+
? { index: '_id_', shard, stage: null, fields: { _id: 1 } }
|
|
66
|
+
: { index: stage.indexName, shard, stage });
|
|
64
67
|
}
|
|
65
68
|
if (this.isSharded) {
|
|
66
69
|
for (const shard of this.executionStats?.executionStages?.shards ?? []) {
|
|
67
|
-
if (!ret.some((
|
|
68
|
-
ret.push({ index: null, shard: shard.shardName,
|
|
70
|
+
if (!ret.some((entry) => entry.shard === shard.shardName)) {
|
|
71
|
+
ret.push({ index: null, shard: shard.shardName, stage: null });
|
|
69
72
|
}
|
|
70
73
|
}
|
|
71
74
|
}
|
|
72
|
-
return ret.filter((
|
|
75
|
+
return ret.filter((entry, index, arr) => arr.findIndex((i) => i.index === entry.index && i.shard === entry.shard) === index);
|
|
76
|
+
}
|
|
77
|
+
async getUsedIndexes() {
|
|
78
|
+
const usedIndexes = [];
|
|
79
|
+
for (const entry of this._getIndexEntries()) {
|
|
80
|
+
const fields = entry.fields ??
|
|
81
|
+
(entry.stage ? await (0, utils_1.getStageIndexFields)(entry.stage) : {});
|
|
82
|
+
if (entry.index === null) {
|
|
83
|
+
usedIndexes.push({ index: null, shard: entry.shard, fields });
|
|
84
|
+
}
|
|
85
|
+
else {
|
|
86
|
+
usedIndexes.push({ index: entry.index, shard: entry.shard, fields });
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
return usedIndexes;
|
|
73
90
|
}
|
|
74
91
|
get isCovered() {
|
|
75
92
|
// @todo (thomas) implement for sharded explain plans
|
|
@@ -103,7 +120,7 @@ class ExplainPlan {
|
|
|
103
120
|
this.findStageByName('CLUSTERED_IXSCAN'));
|
|
104
121
|
}
|
|
105
122
|
get indexType() {
|
|
106
|
-
const indexes = this.
|
|
123
|
+
const indexes = this._getIndexEntries();
|
|
107
124
|
// Currently the CLUSTERED_IXSCAN and EXPRESS_CLUSTERED_IXSCAN do not report
|
|
108
125
|
// any indexes in the winning stage. Even though the query clearly uses
|
|
109
126
|
// an index. And since we can't determine the index used, we will return CLUSTER.
|
|
@@ -181,7 +198,8 @@ class ExplainPlan {
|
|
|
181
198
|
yield* this._getStageIterator(child);
|
|
182
199
|
}
|
|
183
200
|
}
|
|
184
|
-
serialize() {
|
|
201
|
+
async serialize() {
|
|
202
|
+
const usedIndexes = await this.getUsedIndexes();
|
|
185
203
|
return JSON.parse(JSON.stringify({
|
|
186
204
|
namespace: this.namespace,
|
|
187
205
|
parsedQuery: this.parsedQuery,
|
|
@@ -192,7 +210,7 @@ class ExplainPlan {
|
|
|
192
210
|
totalDocsExamined: this.totalDocsExamined,
|
|
193
211
|
originalExplainData: this.originalExplainData,
|
|
194
212
|
executionStats: this.executionStats,
|
|
195
|
-
usedIndexes
|
|
213
|
+
usedIndexes,
|
|
196
214
|
isCovered: this.isCovered,
|
|
197
215
|
isMultiKey: this.isMultiKey,
|
|
198
216
|
inMemorySort: this.inMemorySort,
|
package/dist/utils.d.ts
CHANGED
package/dist/utils.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"utils.d.ts","sourceRoot":"","sources":["../src/utils.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,GAAG,CAAC;AAE/B,
|
|
1
|
+
{"version":3,"file":"utils.d.ts","sourceRoot":"","sources":["../src/utils.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,GAAG,CAAC;AAE/B,wBAAsB,mBAAmB,CACvC,KAAK,EAAE,KAAK,GACX,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAkBjC"}
|
package/dist/utils.js
CHANGED
|
@@ -35,15 +35,15 @@ var __importStar = (this && this.__importStar) || (function () {
|
|
|
35
35
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
36
|
exports.getStageIndexFields = getStageIndexFields;
|
|
37
37
|
const shell_bson_parser_1 = __importStar(require("@mongodb-js/shell-bson-parser"));
|
|
38
|
-
function getStageIndexFields(stage) {
|
|
38
|
+
async function getStageIndexFields(stage) {
|
|
39
39
|
if (stage.stage === 'EXPRESS_IXSCAN' &&
|
|
40
40
|
typeof stage.keyPattern === 'string') {
|
|
41
41
|
// For EXPRESS stages, the keyPattern is a string, which is not valid json.
|
|
42
|
+
// TODO(COMPASS-10806): This was fixed in 9.0. Currently it has not been
|
|
43
|
+
// backported, so we will keep this workaround for now.
|
|
42
44
|
try {
|
|
43
|
-
const result = (0, shell_bson_parser_1.default)(stage.keyPattern, {
|
|
45
|
+
const result = await (0, shell_bson_parser_1.default)(stage.keyPattern, {
|
|
44
46
|
mode: shell_bson_parser_1.ParseMode.Strict,
|
|
45
|
-
allowComments: true,
|
|
46
|
-
allowMethods: true,
|
|
47
47
|
});
|
|
48
48
|
return typeof result === 'string' ? {} : result;
|
|
49
49
|
}
|
package/package.json
CHANGED
|
@@ -13,7 +13,7 @@
|
|
|
13
13
|
"email": "compass@mongodb.com"
|
|
14
14
|
},
|
|
15
15
|
"homepage": "https://github.com/mongodb-js/compass",
|
|
16
|
-
"version": "1.
|
|
16
|
+
"version": "1.6.0",
|
|
17
17
|
"repository": {
|
|
18
18
|
"type": "git",
|
|
19
19
|
"url": "https://github.com/mongodb-js/compass.git"
|
|
@@ -50,12 +50,12 @@
|
|
|
50
50
|
"reformat": "npm run eslint . -- --fix && npm run prettier -- --write ."
|
|
51
51
|
},
|
|
52
52
|
"dependencies": {
|
|
53
|
-
"@mongodb-js/shell-bson-parser": "^
|
|
54
|
-
"mongodb-explain-compat": "^3.3.
|
|
53
|
+
"@mongodb-js/shell-bson-parser": "^2.0.0",
|
|
54
|
+
"mongodb-explain-compat": "^3.3.42"
|
|
55
55
|
},
|
|
56
56
|
"devDependencies": {
|
|
57
|
-
"@mongodb-js/eslint-config-compass": "^1.4.
|
|
58
|
-
"@mongodb-js/mocha-config-compass": "^1.
|
|
57
|
+
"@mongodb-js/eslint-config-compass": "^1.4.31",
|
|
58
|
+
"@mongodb-js/mocha-config-compass": "^1.9.0",
|
|
59
59
|
"@mongodb-js/prettier-config-compass": "^1.2.10",
|
|
60
60
|
"@mongodb-js/tsconfig-compass": "^1.3.2",
|
|
61
61
|
"@types/chai": "^4.2.21",
|
|
@@ -68,5 +68,5 @@
|
|
|
68
68
|
"sinon": "^9.2.3",
|
|
69
69
|
"typescript": "^6.0.3"
|
|
70
70
|
},
|
|
71
|
-
"gitHead": "
|
|
71
|
+
"gitHead": "ffed0669174748402f0d54164e9aaed0949eb888"
|
|
72
72
|
}
|