-
Notifications
You must be signed in to change notification settings - Fork 3.2k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Optimize SQL based on parameter nullability
This is part of #17543 - Queries really slow due to null checks Problem was that at the time we performed null semantics and related optimizations we didn't know the value of parameters, so we always had to assume they can be nullable, which resulted in additional IS NULL checks being created. However, later in the pipeline we know the parameter values and we can optimize out those checks for parameters whose values are not null.
- Loading branch information
Showing
25 changed files
with
578 additions
and
415 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
76 changes: 76 additions & 0 deletions
76
...lShapedQueryCompilingExpressionVisitor.ParameterNullabilityOptimizingExpressionVisitor.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,76 @@ | ||
// Copyright (c) .NET Foundation. All rights reserved. | ||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. | ||
|
||
using System.Collections.Generic; | ||
using System.Linq; | ||
using System.Linq.Expressions; | ||
using Microsoft.EntityFrameworkCore.Query.Internal; | ||
using Microsoft.EntityFrameworkCore.Query.SqlExpressions; | ||
|
||
namespace Microsoft.EntityFrameworkCore.Query | ||
{ | ||
public partial class RelationalShapedQueryCompilingExpressionVisitor | ||
{ | ||
private class ParameterNullabilityBasedSqlExpressionOptimizingExpressionVisitor : SqlExpressionOptimizingExpressionVisitor | ||
{ | ||
private readonly IReadOnlyDictionary<string, object> _parametersValues; | ||
|
||
public ParameterNullabilityBasedSqlExpressionOptimizingExpressionVisitor( | ||
ISqlExpressionFactory sqlExpressionFactory, | ||
bool useRelationalNulls, | ||
IReadOnlyDictionary<string, object> parametersValues) | ||
: base(sqlExpressionFactory, useRelationalNulls) | ||
{ | ||
_parametersValues = parametersValues; | ||
} | ||
|
||
protected override Expression VisitExtension(Expression extensionExpression) | ||
{ | ||
if (extensionExpression is SelectExpression selectExpression) | ||
{ | ||
var newSelectExpression = (SelectExpression)base.VisitExtension(extensionExpression); | ||
|
||
return newSelectExpression.Predicate is SqlConstantExpression newSelectPredicateConstant | ||
&& !(selectExpression.Predicate is SqlConstantExpression) | ||
? newSelectExpression.Update( | ||
newSelectExpression.Projection.ToList(), | ||
newSelectExpression.Tables.ToList(), | ||
SqlExpressionFactory.Equal( | ||
newSelectPredicateConstant, | ||
SqlExpressionFactory.Constant(true, newSelectPredicateConstant.TypeMapping)), | ||
newSelectExpression.GroupBy.ToList(), | ||
newSelectExpression.Having, | ||
newSelectExpression.Orderings.ToList(), | ||
newSelectExpression.Limit, | ||
newSelectExpression.Offset, | ||
newSelectExpression.IsDistinct, | ||
newSelectExpression.Alias) | ||
: newSelectExpression; | ||
} | ||
|
||
return base.VisitExtension(extensionExpression); | ||
} | ||
|
||
protected override Expression VisitSqlUnaryExpression(SqlUnaryExpression sqlUnaryExpression) | ||
{ | ||
var result = base.VisitSqlUnaryExpression(sqlUnaryExpression); | ||
if (result is SqlUnaryExpression newUnaryExpresion | ||
&& newUnaryExpresion.Operand is SqlParameterExpression parameterOperand) | ||
{ | ||
var parameterValue = _parametersValues[parameterOperand.Name]; | ||
if (sqlUnaryExpression.OperatorType == ExpressionType.Equal) | ||
{ | ||
return SqlExpressionFactory.Constant(parameterValue == null, sqlUnaryExpression.TypeMapping); | ||
} | ||
|
||
if (sqlUnaryExpression.OperatorType == ExpressionType.NotEqual) | ||
{ | ||
return SqlExpressionFactory.Constant(parameterValue != null, sqlUnaryExpression.TypeMapping); | ||
} | ||
} | ||
|
||
return result; | ||
} | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.