-
Notifications
You must be signed in to change notification settings - Fork 3.5k
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
Data filters cause database index scan instead of index seek #6680
Comments
What is your sql server version? |
This problem is present on various versions of mssql, I personally checked on version 15 and on Microsoft Azure (the most recent one I guess). It's probably not a database bug, that's how its optimizer works. Perhaps it is necessary to take into account this feature. |
We want to dynamically enable/disable a filter at runtime, I can't find other ways to achieve it. |
You can try to use IgnoreQueryFilters to disable EF Core's global filters. https://docs.microsoft.com/en-us/ef/core/querying/filters#disabling-filters |
Can we change the protected virtual Expression<Func<TEntity, bool>> CreateFilterExpression<TEntity>()
where TEntity : class
{
Expression<Func<TEntity, bool>> expression = null;
if (typeof(ISoftDelete).IsAssignableFrom(typeof(TEntity)))
{
expression = e => !IsSoftDeleteFilterEnabled || !EF.Property<bool>(e, "IsDeleted");
}
if (typeof(IMultiTenant).IsAssignableFrom(typeof(TEntity)))
{
Expression<Func<TEntity, bool>> multiTenantFilter = e => !IsMultiTenantFilterEnabled || EF.Property<Guid>(e, "TenantId") == CurrentTenantId;
expression = expression == null ? multiTenantFilter : CombineExpressions(expression, multiTenantFilter);
}
return expression;
} to protected virtual Expression<Func<TEntity, bool>> CreateFilterExpression<TEntity>()
where TEntity : class
{
Expression<Func<TEntity, bool>> expression = null;
if (typeof(ISoftDelete).IsAssignableFrom(typeof(TEntity)))
{
if (IsSoftDeleteFilterEnabled)
{
expression = e => !EF.Property<bool>(e, "IsDeleted");
}
}
if (typeof(IMultiTenant).IsAssignableFrom(typeof(TEntity)))
{
if (IsMultiTenantFilterEnabled)
{
Expression<Func<TEntity, bool>> multiTenantFilter = e => EF.Property<Guid>(e, "TenantId") == CurrentTenantId;
expression = expression == null ? multiTenantFilter : CombineExpressions(expression, multiTenantFilter);
}
}
return expression;
} avoid add the IsMultiTenantFilterEnabled filter into sql directly |
I cannot understand, why need to add the condition into expression and generate it to sql ,such as IsSoftDeleteFilterEnabled、IsMultiTenantFilterEnabled,what is the exact reason? can we only use it in the logic code? |
@xyfy This update won't work because it is applied in The context lifetime could be cached across requests so the results are going to be inconsistent too: https://docs.microsoft.com/en-us/ef/core/dbcontext-configuration/#the-dbcontext-lifetime |
This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. Thank you for your contributions. |
ABP Framework version: 4.11.0
User Interface: Angular
Steps to reproduce: Run IRepository <TEntity:IMustHaveTenant >.GetAllList() method
Data filters use sql data parameters to show if the filter is enabled or not. These parameters sometimes cause performance issues on MSSQL Server, forcing it to use index scan insted of index seek. This is a huge problem for the tables with large number of records.
For example, here is a sample query with enabled data filter and its execution plan (the query is generated automatically):
As you can see, it performs index scan for a table. For our database this query takes 1.5 minutes to complete.
And this is the same query except removing of the filter parameter (which is redundant here anyway)
![index-seek](https://user-images.githubusercontent.com/8512299/102368737-da629b00-3fc3-11eb-8a64-1dfa7ec01d52.png)
declare @__ef_filter__CurrentTenantId_1 int = 1
SELECT top 100 * FROM [Prospects] AS [e] WHERE ([e].[TenantId] = @__ef_filter__CurrentTenantId_1)
And now it uses index seek. This query completes in < 1s on the same database.
The main issue for the MS SQL server is this one: https://stackoverflow.com/questions/27564852/why-is-sql-server-using-index-scan-instead-of-index-seek-when-where-clause-conta
There is no way to prevent data filter to modify the SQL query. Disabling the filter just sets its parameter value to 0.
Suggestion: to avoid using bit parameters in data filters. Such filter should be applied or not before goes down to SQL.
The text was updated successfully, but these errors were encountered: