-
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
Consider removing the CAST to BIT for boolean literal values #27150
Comments
Is hierarchyid officially supported in the SQL Server provider? |
There's an unofficial extension we maintain. But my fear is that if there's a different plan in this case, there could be other cases we don't know about. Yet another example that generating minimal/lighter SQL is always a good idea. |
I'm curious as if, in the meanwhile, there anything that our code can tap into to hotfix, before this issue gets to see daylight? |
A command interceptor is probably the reasonable thing to do here: you would identify commands that do hierarchy operations (either by tagging them with EF Core, or simply by searching for hierarchy ID function names), and replace |
Blocked on #15586 |
The general objective here is to end up with If I understand correctly, the approach blocked on #15586 would involve comparing to an int (requiring knowledge on what's comparable to what in SQL). An alternative would be to simply change the literal representation in SqlServerBoolTypeMapping to simply not have the CAST. This would cause issues when a bool constant is being projected (#24075), since a bare 1 or 0 can't be read into a .NET bool. I think that should be considered as part of the more global problem of projecting constant representations with evaluate to a different type - continuing this thought in #24075. |
I am currently running in this issue, is there a work around for this ? |
@iduras3 see the command interceptor approach discussed above. |
We're seeing a very similar issue however we're using external tables in Azure SQL. It's supposed to push the WHERE clause to the remote database server but having a In the example below, we're using EF global filters to not pull back any soft deleted records
|
For a detailed look at the bool/bit cast problem on the global QueryFilter. |
For folks who come to this issue and are interested, this is what I came up with for the Interceptor suggestion. It handles the projection problem by checking to see if the CAST is happening right before /// <summary>
/// Intercepter to replace the <c>CAST(0 AS bit)</c> with <c>0</c> and <c>CAST(1 AS bit)</c> with <c>1</c>.
/// This works around https://github.com/dotnet/efcore/issues/27150 which can cause performance issues.
/// </summary>
/// <remarks>Does not replace <c>CAST(0 AS bit)</c> when followed by <c>AS [somename]</c> so as not to break projection. Also doesn't do the replacement in the scenario of CASE THEN ELSE results.</remarks>
internal partial class BooleanCommandInterceptor : DbCommandInterceptor
{
[GeneratedRegex(@"(?<!\bTHEN\s+|\bELSE\s+)CAST\((0|1) AS bit\)(?!\s+AS\s+\[\w+\])")]
private static partial Regex BitCastRegex();
public override InterceptionResult<DbDataReader> ReaderExecuting(
DbCommand command,
CommandEventData eventData,
InterceptionResult<DbDataReader> result)
{
ManipulateCommand(command);
return result;
}
public override ValueTask<InterceptionResult<DbDataReader>> ReaderExecutingAsync(
DbCommand command,
CommandEventData eventData,
InterceptionResult<DbDataReader> result,
CancellationToken cancellationToken = default)
{
ManipulateCommand(command);
return new ValueTask<InterceptionResult<DbDataReader>>(result);
}
private static void ManipulateCommand(DbCommand command)
{
var matches = BitCastRegex().Matches(command.CommandText);
if (matches.Count != 0)
{
command.CommandText = BitCastRegex().Replace(command.CommandText, "$1");
}
}
} Edit: 10/15, fixed a problem where CASE THEN ELSE wouldn't work because it was removing the cast from the results. Fixed that. |
Our SQL representation of boolean literal values is
CAST(1 AS BIT)
. However, in at least some cases, the CAST produces an inferior query plan. The following example shows this when calling hierarchyid's IsDescendantOf:Hierarchyid plan without CAST
Plan:
Hierarchyid plan with CAST
Plan:
Test SQL
hierarchyid test
Note that in other scenarios, e.g. simply comparing a regular BIT column to literal true/false, the degradation does not occur (this could be specific to hierarchyid, though who knows):
Regular column test
Flagged by @diogonborges in #23472 (comment)
The text was updated successfully, but these errors were encountered: