|
Consider these two queries:
db.coll.find({}, {a: ["foo"]});
|
|
db.coll.aggregate([{$project: {a: ["foo"]}}]);
|
They are entirely identical in meaning and should return the same result set. The only difference between them is that the former is expressed as a find command and the latter is expressed as an aggregate command.
Explaining both queries shows that the find command uses the classic execution engine and the aggregate command uses SBE. This difference could potentially surprise users, in particular by leading to different performance properties (or by leading to differences in diagnostic output, e.g. radically different explain output). Ideally we would guarantee that when a find is re-expressed as an aggregate or vice-versa, the classic vs. SBE engine selection rules do not also change.
The reason for the different engine selection relates to whether SBE compatibility is checked before or after pipeline optimization. For find, the sbeCompatible flag is set at parse time. For agg, the sbeCompatible flag is set only after some optimizations have taken place. This happens because agg resets the sbeCompatible flag to true here. This is done to deal with the case where the full query has some SBE incompatible properties, but the portion of the query pushed down to the find layer is SBE compatible.
In this particular example, ["foo"] is interpreted by the parser as an ExpressionArray, which is SBE incompatible. However, it can subsequently be optimized to an ExpressionConstant which effectively converts an SBE incompatible query into an SBE compatible one. This is the only case I'm aware of where an optimization can render a formerly incompatible query compatible with SBE, but there could be others.
|