-
Notifications
You must be signed in to change notification settings - Fork 3.2k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Optimize DISTINCT over singleton collections #34702
Conversation
@@ -255,6 +255,11 @@ public void ApplyDistinct() | |||
throw new InvalidOperationException(RelationalStrings.DistinctOnCollectionNotSupported); | |||
} | |||
|
|||
if (Limit is SqlConstantExpression { Value: 0 or 1 }) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
does it make sense to handle the case of 0
? AFAICT SELECT
expressions with a LIMIT 0
could be optimized away heavily (basically only the projection/typing matters; offset, predicate, distinct, ... are all irrelevant)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah, I agree - if we want to optimize the LIMIT 0
case, we should probably do that separately and go much farther than just removing DISTINCT... Any thoughts on cases where LIMIT 0
could be an actually useful thing to do (and therefore worth working on)?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
A corner case where a LIMIT of 0 is sometimes used (that I know of) is in paginated queries that (ab?)use it to only retrieve the count of the relevant entities, but that is usually going to be handled as a 0-valued parameter.
@@ -1901,6 +1906,10 @@ public void ApplyLimit(SqlExpression sqlExpression) | |||
} | |||
|
|||
Limit = sqlExpression; | |||
if (Offset is null && Limit is SqlConstantExpression { Value: 0 or 1 }) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nit:
if (Offset is null && Limit is SqlConstantExpression { Value: 0 or 1 }) | |
if (Offset is null && Limit is SqlConstantExpression { Value: 0 or 1 }) |
@@ -255,6 +255,11 @@ public void ApplyDistinct() | |||
throw new InvalidOperationException(RelationalStrings.DistinctOnCollectionNotSupported); | |||
} | |||
|
|||
if (Limit is SqlConstantExpression { Value: 0 or 1 }) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah, I agree - if we want to optimize the LIMIT 0
case, we should probably do that separately and go much farther than just removing DISTINCT... Any thoughts on cases where LIMIT 0
could be an actually useful thing to do (and therefore worth working on)?
2edd5b9
to
41482f6
Compare
41482f6
to
a592e72
Compare
I dropped the limit=0 cases; if optimizations are desired for them, they can be way more aggressive and best handled separately (as they basically drop any rows). |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks @ranma42!
This does some progress towards fixing #34482, but in several cases the optimization does not trigger because of another intermediate operation.
I will investigate whether it makes sense to combine these operations in a separate PR or if they can be easily handled in this one.
The
Single/First[OrDefault]
case seems to be reasonably tested; for theTake(1)
case it might be better to add a new test (it is tested, but AFAICT only in combination withSingle/First[OrDefault]
).