-
Notifications
You must be signed in to change notification settings - Fork 3.2k
New issue
Have a question about this project? # for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “#”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? # 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]
).