summaryrefslogtreecommitdiff
path: root/jstests/sharding/queries_elide_shard_filter.js
blob: ab0fbb5ecadba27c85cddaa28ea8baffa98f4a8a (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
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
//
// Tests that queries in sharded collections will be properly optimized. In particular, queries
// which specify the shard key fully with an equality predicate may omit a SHARDING_FILTER stage.
//
// @tags: [requires_fcv_49]

(function() {
"use strict";

load("jstests/libs/analyze_plan.js");

function assertShardFilter(explain) {
    const filterStage = getPlanStage(explain.queryPlanner.winningPlan, "SHARDING_FILTER");
    assert.eq(filterStage.stage, "SHARDING_FILTER");
    const scanStage = filterStage.inputStage;
    assert.contains(scanStage.stage, ["IXSCAN", "FETCH"]);
}

function assertNoShardFilter(explain) {
    const filterStage = getPlanStage(explain.queryPlanner.winningPlan, "SHARDING_FILTER");
    assert.eq(filterStage, null, explain);
}

function assertCountScan(explain) {
    const countStage = getPlanStage(explain.queryPlanner.winningPlan, "COUNT_SCAN");
    assert.eq(countStage.stage, "COUNT_SCAN");
}

const st = new ShardingTest({shards: 1});
const coll = st.s0.getCollection("foo.bar");

function createCollection(coll, shardKey) {
    coll.drop();
    assert.commandWorked(st.s0.adminCommand({shardCollection: coll.getFullName(), key: shardKey}));

    assert.commandWorked(coll.insert({_id: true, a: true, b: true, c: true, d: true}));
    assert.commandWorked(coll.createIndex({a: 1, b: 1}));
    assert.commandWorked(coll.createIndex({b: 1, a: 1}));
}

assert.commandWorked(st.s0.adminCommand({enableSharding: coll.getDB().getName()}));

jsTest.log('Tests with single shard key');
createCollection(coll, {a: 1});

// We're requesting a specific shard key, therefore we should optimize away SHARDING_FILTER
// and use a cheaper COUNT_SCAN.
let explain = assert.commandWorked(coll.explain('executionStats').count({a: true}));
assertCountScan(explain);
// Check this works with a subset of records as well.
explain = assert.commandWorked(coll.explain('executionStats').count({a: true, b: true}));
assertCountScan(explain);

// Test that a find() query which specifies the entire shard key does not need a shard filter.
explain = assert.commandWorked(coll.find({a: true}).explain());
assertNoShardFilter(explain);
explain = assert.commandWorked(coll.find({a: true, b: true}).explain());
assertNoShardFilter(explain);

// We're not checking shard key for equality, therefore need a sharding filter.
explain = assert.commandWorked(coll.explain('executionStats').count({a: {$in: [true, false]}}));
assertShardFilter(explain);

// We're requesting a disjoint key from shardkey, therefore need a sharding filter.
explain = assert.commandWorked(coll.explain('executionStats').count({b: true}));
assertShardFilter(explain);

jsTest.log('Tests with compound shard key');
createCollection(coll, {a: 1, b: 1});

explain = assert.commandWorked(coll.explain('executionStats').count({a: true}));
assertShardFilter(explain);
explain = assert.commandWorked(coll.explain('executionStats').count({a: true, b: true}));
assertCountScan(explain);
explain =
    assert.commandWorked(coll.explain('executionStats').count({a: true, b: {$in: [true, false]}}));
assertShardFilter(explain);

explain = assert.commandWorked(coll.find({a: true}).explain());
assertShardFilter(explain);
explain = assert.commandWorked(coll.find({a: true, b: true}).explain());
assertNoShardFilter(explain);
explain = assert.commandWorked(coll.find({a: true, b: {$in: [true, false]}}).explain());
assertShardFilter(explain);

jsTest.log('Tests with hashed shard key');
createCollection(coll, {a: 'hashed'});

explain = assert.commandWorked(coll.explain('executionStats').count({a: true}));
assertCountScan(explain);
explain = assert.commandWorked(coll.explain('executionStats').count({a: true, b: true}));
assertCountScan(explain);
explain = assert.commandWorked(coll.explain('executionStats').count({a: {$in: [true, false]}}));
assertShardFilter(explain);
explain = assert.commandWorked(coll.explain('executionStats').count({b: true}));
assertShardFilter(explain);

explain = assert.commandWorked(coll.find({a: true}).explain());
assertNoShardFilter(explain);
explain = assert.commandWorked(coll.find({a: true, b: true}).explain());
assertNoShardFilter(explain);
explain = assert.commandWorked(coll.find({a: {$in: [true, false]}}).explain());
assertShardFilter(explain);
explain = assert.commandWorked(coll.find({b: true}).explain());
assertShardFilter(explain);

st.stop();
})();