Files
mongo/jstests/sharding/query/explain/explain_exec_stats_on_shards.js
Zac 591928c619 SERVER-108478 JS formatted by prettier and remove clang-format (#39656)
GitOrigin-RevId: 6c8f6aded47f260aa4f7c231b17dae3302cb1e04
2025-08-21 17:27:09 +00:00

142 lines
6.6 KiB
JavaScript

// Tests for the mongos explain command to ensure that the 'executionStats' section of the explain
// output is populated correctly for each shard.
// Verifies that the explain output for the given shard contains all expected fields and that
// field values match the values specified in the 'expected*' arguments. This function also
// updates the 'totals' object which holds accumulated values for certain fields from each
// shard.
import {ShardingTest} from "jstests/libs/shardingtest.js";
function verifyExecStatsOnShard({
explain,
expectedShardName,
expectedNReturned,
expectedKeysExamined,
expectedDocsExamined,
totals,
}) {
assert(explain.executionSuccess, tojson(explain));
assert.eq(explain.shardName, expectedShardName, tojson(explain));
assert.eq(explain.nReturned, expectedNReturned, tojson(explain));
assert.gte(explain.executionTimeMillis, 0, tojson(explain));
assert.eq(explain.totalKeysExamined, expectedKeysExamined, tojson(explain));
assert.eq(explain.totalDocsExamined, expectedDocsExamined, tojson(explain));
assert(explain.hasOwnProperty("executionStages"), tojson(explain));
totals.nReturned += explain.nReturned;
totals.executionTimeMillis += explain.executionTimeMillis;
totals.keysExamined += explain.totalKeysExamined;
totals.docsExamined += explain.totalDocsExamined;
}
// Create a cluster with 2 shards.
const numShards = 2;
const st = new ShardingTest({shards: numShards});
const db = st.s.getDB(`${jsTest.name()}_db`);
// Enable sharding on the database and use shard0 as the primary shard.
assert.commandWorked(db.adminCommand({enableSharding: db.getName(), primaryShard: st.shard0.shardName}));
// Test that the explain's 'executionStats' section includes all relevant fields for each shard
// when the 'explain' command is executed against a sharded collection.
(function testExplainExecutionStatsWithShardedCollection() {
// Set up a collection, shard on {a:1}, split at {a:4}, and move the {a:4} chunk to shard1.
const shardedColl = db.getCollection(`${jsTest.name()}_sharded`);
shardedColl.drop();
st.shardColl(shardedColl, {a: 1}, {a: 4}, {a: 4});
// Put documents on each shard.
const numDocs = 10;
for (let i = 0; i < numDocs; i++) {
assert.commandWorked(shardedColl.insert({_id: i, a: i}));
}
assert.eq(shardedColl.find().itcount(), numDocs);
// Explain the find command and check that all expected explain fields are present in the
// output.
const explain = shardedColl.find({}).explain("executionStats");
assert(explain.hasOwnProperty("executionStats"), tojson(explain));
assert(explain.executionStats.hasOwnProperty("executionStages"), tojson(explain));
assert(explain.executionStats.executionStages.hasOwnProperty("shards"), tojson(explain));
assert.eq(explain.executionStats.executionStages.shards.length, numShards);
// Verify execution stats on each shards and accumulate totals.
const totals = {nReturned: 0, executionTimeMillis: 0, keysExamined: 0, docsExamined: 0};
const executionStages = explain.executionStats.executionStages;
// Sort the shards array by the 'shardName' to guarantee consistent results, as explain
// outputs from the shards may arrive in an arbitrary order.
executionStages.shards.sort((a, b) => a.shardName.localeCompare(b.shardName));
let sortedExpectedStats = [
{
expectedShardName: st.shard0.shardName,
expectedNReturned: 4,
expectedKeysExamined: 0,
expectedDocsExamined: 4,
totals: totals,
},
{
expectedShardName: st.shard1.shardName,
expectedNReturned: 6,
expectedKeysExamined: 0,
expectedDocsExamined: 6,
totals: totals,
},
];
sortedExpectedStats.sort((a, b) => a.expectedShardName.localeCompare(b.expectedShardName));
verifyExecStatsOnShard(Object.merge(sortedExpectedStats[0], {explain: executionStages.shards[0]}));
verifyExecStatsOnShard(Object.merge(sortedExpectedStats[1], {explain: executionStages.shards[1]}));
// Ensure that execution stats accumulated across all shards matches the values in the
// top-level 'executionStages' section of the explain output.
assert.eq(executionStages.nReturned, totals.nReturned, tojson(explain));
assert.eq(executionStages.totalChildMillis, totals.executionTimeMillis, tojson(explain));
assert.eq(executionStages.totalKeysExamined, totals.keysExamined, tojson(explain));
assert.eq(executionStages.totalDocsExamined, totals.docsExamined, tojson(explain));
})();
// Test that the explain's 'executionStats' section includes all relevant fields when the
// 'explain' command is executed against an unsharded collection.
(function testExplainExecutionStatsWithUnshardedCollection() {
// Setup an unsharded collection.
const unshardedColl = db.getCollection(`${jsTest.name()}_unsharded`);
unshardedColl.drop();
assert.commandWorked(unshardedColl.createIndex({a: 1}));
// Add documents to the collection.
const numDocs = 10;
for (let i = 0; i < numDocs; i++) {
assert.commandWorked(unshardedColl.insert({_id: i, a: i}));
}
assert.eq(unshardedColl.count(), numDocs);
// Explain the find command and check that all expected explain fields are present in the
// output.
const explain = unshardedColl.find({}).explain("executionStats");
assert(explain.hasOwnProperty("executionStats"), tojson(explain));
assert(explain.executionStats.hasOwnProperty("executionStages"), tojson(explain));
assert(explain.executionStats.executionStages.hasOwnProperty("shards"), tojson(explain));
assert.eq(explain.executionStats.executionStages.shards.length, 1);
// Verify execution stats on the primary shard and accumulate totals.
const totals = {nReturned: 0, executionTimeMillis: 0, keysExamined: 0, docsExamined: 0};
const executionStages = explain.executionStats.executionStages;
verifyExecStatsOnShard({
explain: executionStages.shards[0],
expectedShardName: st.shard0.shardName,
expectedNReturned: 10,
expectedKeysExamined: 0,
expectedDocsExamined: 10,
totals: totals,
});
// Ensure that execution stats on the primary shard matches the values in the top-level
// 'executionStages' section of the explain output.
assert.eq(executionStages.nReturned, totals.nReturned, tojson(explain));
assert.eq(executionStages.totalChildMillis, totals.executionTimeMillis, tojson(explain));
assert.eq(executionStages.totalKeysExamined, totals.keysExamined, tojson(explain));
assert.eq(executionStages.totalDocsExamined, totals.docsExamined, tojson(explain));
})();
st.stop();