MONGOID-5030 - Skip contradicting queries #5734
Open
Add this suggestion to a batch that can be applied as a single commit. This suggestion is invalid because no changes were made to the code. Suggestions cannot be applied while the pull request is closed. Suggestions cannot be applied while viewing a subset of changes. Only one suggestion per line can be applied in a batch. Add this suggestion to a batch that can be applied as a single commit. Applying suggestions on deleted lines is not supported. You must change the existing code in this line in order to create a valid suggestion. Outdated suggestions cannot be applied. This suggestion has been applied or marked resolved. Suggestions cannot be applied from pending reviews. Suggestions cannot be applied on multi-line comments. Suggestions cannot be applied while the pull request is queued to merge. Suggestion cannot be applied right now. Please check back later.
(This PR is currently a Proof-of-Concept.)
What?
This PR implements short-circuit logic for the
$in
,$nin
, and equality operators, in cases where the query condition deterministically results in a "none" result.Why?
When we upgraded to MongoDB 7.0.2 from 6.x, we discovered the hard way (~4 hours of downtime) that the new Slot-Based Query Execution Engine (SBQEE) behaves differently than the Classic Engine.
In particular, we had a query with a shape like this in a collection with 250M+ records:
Previously, when
table_ids: { "$in" => [] }
(empty array) was present, the Classic Engine was optimized to skip the query. However, the SBQEE does a full collection scan. If these queries pile-up, database CPU goes to 100% and its game over. We believe this behavior is a bug; SERVER ticket coming soon.Solution
In MONGOID-5030 which I raised in 2020, I proposed to short-circuit these queries. ActiveRecord 6.1 did this in this PR. At the time the MongoDB answered that the query engine was optimized to skip the queries, but I think the introduction of the SBQEE makes this more urgent.
I considered 3 possible approaches:
Criteria.in
method, at the time conditions are added to the selector.Mongoid::Contextual::Mongo
before the query goes to the driver, and detect contradictions in the final query.Option #1 has the disadvantage that it doesn't cover cases like
Person.where(name: { "$in" => [] })
, so I ruled it out. Option #3 I investigated, but it would require introducing the concept of a "Null Operation" to the driver, which increases complexity. Option #2 we already have a precedent withMongoid::Contextual::None
so it might be the best approach.This PR is currently a POC to illustrate where I will insert the logic. I will add a feature flag for this, however, I believe it is safe to implement.
Truth Tables
For reference. These tables illustrate the logic that can be short circuited. This PR will only cover the
none
case.$in
none
)none
)none
)all
)all
)$nin
all
)all
)none
)none
)