summaryrefslogtreecommitdiff
path: root/jstests/core/distinct_index1.js
blob: e1cd721c7f4e4cd408ae8caa95396d2e5a119da4 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
/**
 * Analyzes execution stats for indexed distinct.
 * @tags: [assumes_balancer_off]
 */
(function() {
load("jstests/libs/analyze_plan.js");  // For getPlanStage.

const coll = db.distinct_index1;
coll.drop();

function getHash(num) {
    return Math.floor(Math.sqrt(num * 123123)) % 10;
}

function getDistinctExplainWithExecutionStats(field, query) {
    const explain = coll.explain("executionStats").distinct(field, query || {});
    assert(explain.hasOwnProperty("executionStats"), explain);
    return explain;
}

const bulk = coll.initializeUnorderedBulkOp();
for (let i = 0; i < 1000; i++) {
    bulk.insert({a: getHash(i * 5), b: getHash(i)});
}
assert.commandWorked(bulk.execute());

let explain = getDistinctExplainWithExecutionStats("a");
// Collection scan looks at all 1000 documents and gets 1000 distinct values. Looks at 0 index
// keys.
assert.eq(1000, explain.executionStats.nReturned);
assert.eq(0, explain.executionStats.totalKeysExamined);
assert.eq(1000, explain.executionStats.totalDocsExamined);

explain = getDistinctExplainWithExecutionStats("a", {a: {$gt: 5}});
// Collection scan looks at all 1000 documents and gets 398 distinct values which match the
// query. Looks at 0 index keys.
assert.eq(398, explain.executionStats.nReturned);
assert.eq(0, explain.executionStats.totalKeysExamined);
assert.eq(1000, explain.executionStats.totalDocsExamined);

explain = getDistinctExplainWithExecutionStats("b", {a: {$gt: 5}});
// Collection scan looks at all 1000 documents and gets 398 distinct values which match the
// query. Looks at 0 index keys.
assert.eq(398, explain.executionStats.nReturned);
assert.eq(0, explain.executionStats.totalKeysExamined);
assert.eq(1000, explain.executionStats.totalDocsExamined);

assert.commandWorked(coll.createIndex({a: 1}));

explain = getDistinctExplainWithExecutionStats("a");
// There are only 10 values.  We use the fast distinct hack and only examine each value once.
assert.eq(10, explain.executionStats.nReturned);
assert.lte(10, explain.executionStats.totalKeysExamined);

explain = getDistinctExplainWithExecutionStats("a", {a: {$gt: 5}});
// Only 4 values of a are >= 5 and we use the fast distinct hack.
assert.eq(4, explain.executionStats.nReturned);
assert.eq(4, explain.executionStats.totalKeysExamined);
assert.eq(0, explain.executionStats.totalDocsExamined);

explain = getDistinctExplainWithExecutionStats("b", {a: {$gt: 5}});
// We can't use the fast distinct hack here because we're distinct-ing over 'b'.
assert.eq(398, explain.executionStats.nReturned);
assert.eq(398, explain.executionStats.totalKeysExamined);
assert.eq(398, explain.executionStats.totalDocsExamined);

// Test that a distinct over a trailing field of the index can be covered.
assert.commandWorked(coll.dropIndexes());
assert.commandWorked(coll.createIndex({a: 1, b: 1}));
explain = getDistinctExplainWithExecutionStats("b", {a: {$gt: 5}, b: {$gt: 5}});
assert.lte(explain.executionStats.nReturned, 171);
assert.eq(0, explain.executionStats.totalDocsExamined);

// Should use an index scan over the hashed index.
assert.commandWorked(coll.dropIndexes());
assert.commandWorked(coll.createIndex({a: "hashed"}));
explain = getDistinctExplainWithExecutionStats("a", {$or: [{a: 3}, {a: 5}]});
assert.eq(188, explain.executionStats.nReturned);
const indexScanStage = getPlanStage(explain.executionStats.executionStages, "IXSCAN");
assert.eq("hashed", indexScanStage.keyPattern.a);
})();