添加针对并发查询条件下使用asnotracking查询提高性能

This commit is contained in:
xuejmnet 2021-11-29 21:35:54 +08:00
parent e61e50693c
commit 7a302b8597
16 changed files with 52 additions and 31 deletions

View File

@ -56,7 +56,7 @@ namespace Sample.SqlServer.Controllers
userId = u.Id
};
var listAsync = await sql.ToListAsync();
var resultx112331tt = await _defaultTableDbContext.Set<SysTest>().CountAsync();
var resultx112331tt = await _defaultTableDbContext.Set<SysTest>().AsNoTracking().CountAsync();
var resultx112331 = await _defaultTableDbContext.Set<SysUserMod>().CountAsync();
var resultx11233411 = _defaultTableDbContext.Set<SysUserMod>().Count();
var resultx11231 = await _defaultTableDbContext.Set<SysUserMod>().Where(o => o.Age == 198198).Select(o => o.Id).ContainsAsync("1981");

View File

@ -49,7 +49,8 @@ namespace ShardingCore.Core.EntityMetadatas
return this;
}
/// <summary>
/// 是否启动建表
/// 是否启动的时候创建表,仅在启动时判断该属性,如果你是按时间分表的那么这个属性将不会在特定时间创建对应的表信息需要手动进行表创建和添加
/// 当然您也可以使用系统默认的时间路由通过重写AutoCreateByTime方法重写返回true来保证sharding_core开启定时任务并且已经集成自动创建表和库
/// </summary>
/// <param name="autoCreate"></param>
/// <returns></returns>

View File

@ -86,6 +86,9 @@ namespace ShardingCore.DIExtensions
public bool? CreateShardingTableOnStart { get; set; }
/// <summary>
/// 是否自动追踪实体
/// 譬如本次查询涉及到a1,a2,a3这三张表会创建3个dbcontext进行查询如果AutoTrackEntity=false那么针对被创建的dbcontext不会有任何变化还是以追踪的形式查询
/// 因为会同时创建3个dbcontext所以针对跨表查询完成后dbcontext会被回收但是查询还是按原先的行为查询所以如果不启用建议在查询的时候使用notracking
/// 如果AutoTrackEntity=true那么被创建的三个dbcontext还是以原先的表现行为进行查询在查询完成后会再次各自创建对应的dbcontext进行对象的追踪
/// </summary>
public bool AutoTrackEntity { get; set; }

View File

@ -28,15 +28,6 @@ namespace ShardingCore.DbContexts
{
shardingTableDbContext.RouteTail = routeTail;
}
//if (dbContext is IShardingDbContext shardingDbContext)
//{
// shardingDbContext.ShardingUpgrade();
//}
//else
//{
// throw new ShardingCoreException($"{dbContext.GetType().FullName} should implements {nameof(IShardingDbContext)}");
//}
var dbContextModel = dbContext.Model;
return dbContext;
}

View File

@ -78,10 +78,11 @@ namespace ShardingCore.Extensions
/// </summary>
/// <param name="source">元数据源</param>
/// <param name="dbContext">新数据源</param>
/// <param name="isParallelQuery">是否是并行查询,是的话直接启用asnotracking</param>
/// <returns></returns>
internal static IQueryable ReplaceDbContextQueryable(this IQueryable source, DbContext dbContext)
internal static IQueryable ReplaceDbContextQueryable(this IQueryable source, DbContext dbContext,bool isParallelQuery)
{
DbContextReplaceQueryableVisitor replaceQueryableVisitor = new DbContextReplaceQueryableVisitor(dbContext);
DbContextReplaceQueryableVisitor replaceQueryableVisitor = new DbContextReplaceQueryableVisitor(dbContext,isParallelQuery);
var newExpression = replaceQueryableVisitor.Visit(source.Expression);
return replaceQueryableVisitor.Source.Provider.CreateQuery(newExpression);
}

View File

@ -72,7 +72,7 @@ namespace ShardingCore.Sharding.MergeEngines.Abstractions.InMemoryMerge
{
var shardingDbContext = _mergeContext.CreateDbContext(dsname, tableRouteResult);
var newQueryable = (IQueryable<TEntity>)GetStreamMergeContext().GetReWriteQueryable()
.ReplaceDbContextQueryable(shardingDbContext);
.ReplaceDbContextQueryable(shardingDbContext,_mergeContext.IsParallelQuery());
var newCombineQueryable = DoCombineQueryable<TResult>(newQueryable);
return newCombineQueryable
;

View File

@ -116,7 +116,7 @@ namespace ShardingCore.Sharding.StreamMergeEngines.EnumeratorStreamMergeEngines.
{
var shardingDbContext = StreamMergeContext.CreateDbContext(dsname, sequenceResult.TableRouteResult);
var newQueryable = (IQueryable<TEntity>)(noPaginationQueryable.Skip(sequenceResult.Skip).Take(sequenceResult.Take).OrderWithExpression(reSetOrders))
.ReplaceDbContextQueryable(shardingDbContext);
.ReplaceDbContextQueryable(shardingDbContext,StreamMergeContext.IsParallelQuery());
return newQueryable;
}

View File

@ -48,7 +48,7 @@ namespace ShardingCore.Sharding.MergeEngines.EnumeratorStreamMergeEngines.Enumer
{
var shardingDbContext = StreamMergeContext.CreateDbContext(dsname,tableRouteResult);
var newQueryable = (IQueryable<TEntity>)StreamMergeContext.GetReWriteQueryable()
.ReplaceDbContextQueryable(shardingDbContext);
.ReplaceDbContextQueryable(shardingDbContext,StreamMergeContext.IsParallelQuery());
return newQueryable;
}

View File

@ -63,7 +63,7 @@ namespace ShardingCore.Sharding.StreamMergeEngines.EnumeratorStreamMergeEngines.
{
var shardingDbContext = StreamMergeContext.CreateDbContext(dsname,tableRouteResult);
var newQueryable = (IQueryable<TEntity>)reverseOrderQueryable
.ReplaceDbContextQueryable(shardingDbContext);
.ReplaceDbContextQueryable(shardingDbContext,StreamMergeContext.IsParallelQuery());
return newQueryable;
}

View File

@ -103,7 +103,7 @@ namespace ShardingCore.Sharding.StreamMergeEngines.EnumeratorStreamMergeEngines.
{
var shardingDbContext = StreamMergeContext.CreateDbContext(dsname,sequenceResult.TableRouteResult);
var newQueryable = (IQueryable<TEntity>)(noPaginationQueryable.Skip(sequenceResult.Skip).Take(sequenceResult.Take))
.ReplaceDbContextQueryable(shardingDbContext);
.ReplaceDbContextQueryable(shardingDbContext,StreamMergeContext.IsParallelQuery());
return newQueryable;
}

View File

@ -28,7 +28,7 @@ namespace ShardingCore.Sharding.StreamMergeEngines.EnumeratorStreamMergeEngines.
var dataSourceName = StreamMergeContext.DataSourceRouteResult.IntersectDataSources.First();
var routeResult = StreamMergeContext.TableRouteResults.First();
var shardingDbContext = StreamMergeContext.CreateDbContext(dataSourceName,routeResult);
var newQueryable = (IQueryable<TEntity>) StreamMergeContext.GetOriginalQueryable().ReplaceDbContextQueryable(shardingDbContext);
var newQueryable = (IQueryable<TEntity>) StreamMergeContext.GetOriginalQueryable().ReplaceDbContextQueryable(shardingDbContext,StreamMergeContext.IsParallelQuery());
if (async)
{
var asyncEnumerator = GetAsyncEnumerator0(newQueryable).WaitAndUnwrapException();

View File

@ -18,6 +18,9 @@ namespace ShardingCore.Sharding.ShardingDbContextExecutors
* @Ver: 1.0
* @Email: 326308290@qq.com
*/
/// <summary>
/// 同数据源下的dbcontext管理者
/// </summary>
public interface IDataSourceDbContext : IDisposable
#if !EFCORE2
, IAsyncDisposable

View File

@ -11,15 +11,28 @@ using ShardingCore.Extensions;
*/
namespace ShardingCore.Sharding.ShardingDbContextExecutors
{
/// <summary>
/// 未分表后缀dbcontext排序器
/// 用来针对data source db context多个迭代的时候优先级,默认未分表的排在第一格
/// </summary>
public class NoShardingFirstComparer:IComparer<string>
{
private readonly string _defaultTail;
/// <summary>
/// 未分表后缀dbcontext排序器
/// </summary>
public NoShardingFirstComparer()
{
_defaultTail = new SingleQueryRouteTail(string.Empty).GetRouteTailIdentity();
}
/// <summary>
/// 当 x或者y为默认为分表后缀那么就将对应的排序指定顺序x返回-1y返回1不进行比较
/// </summary>
/// <param name="x"></param>
/// <param name="y"></param>
/// <returns></returns>
public int Compare(string? x, string? y)
{
if (_defaultTail.Equals(x))

View File

@ -74,7 +74,7 @@ namespace ShardingCore.Sharding.ShardingDbContextExecutors
private IDataSourceDbContext GetDataSourceDbContext(string dataSourceName)
{
return _dbContextCaches.GetOrAdd(dataSourceName, dsname => new DataSourceDbContext<TShardingDbContext>(dataSourceName, _virtualDataSource.IsDefault(dataSourceName), _shardingDbContext, _shardingDbContextOptionsBuilderConfig, _shardingDbContextFactory, _actualConnectionStringManager));
return _dbContextCaches.GetOrAdd(dataSourceName, dsname => new DataSourceDbContext<TShardingDbContext>(dsname, _virtualDataSource.IsDefault(dsname), _shardingDbContext, _shardingDbContextOptionsBuilderConfig, _shardingDbContextFactory, _actualConnectionStringManager));
}
/// <summary>

View File

@ -215,7 +215,7 @@ namespace ShardingCore.Sharding
/// 是否使用并行查询
/// </summary>
/// <returns></returns>
private bool IsParallelQuery()
public bool IsParallelQuery()
{
return !_shardingConfigOption.AutoTrackEntity|| IsCrossQuery() || IsUseReadWriteSeparation();
}

View File

@ -19,11 +19,13 @@ namespace ShardingCore.Core.Internal.Visitors
internal class DbContextReplaceQueryableVisitor : ExpressionVisitor
{
private readonly DbContext _dbContext;
private readonly bool _isParallelQuery;
public IQueryable Source;
public DbContextReplaceQueryableVisitor(DbContext dbContext)
public DbContextReplaceQueryableVisitor(DbContext dbContext, bool isParallelQuery)
{
_dbContext = dbContext;
_isParallelQuery = isParallelQuery;
}
protected override Expression VisitConstant(ConstantExpression node)
@ -32,8 +34,11 @@ namespace ShardingCore.Core.Internal.Visitors
{
var dbContextDependencies = typeof(DbContext).GetTypePropertyValue(_dbContext, "DbContextDependencies") as IDbContextDependencies;
var targetIQ = (IQueryable)((IDbSetCache)_dbContext).GetOrAddSet(dbContextDependencies.SetSource, queryable.ElementType);
//var newQueryable = targetIQ.Provider.CreateQuery((Expression) Expression.Call((Expression) null, typeof(EntityFrameworkQueryableExtensions).GetTypeInfo().GetDeclaredMethod("AsNoTracking").MakeGenericMethod(queryable.ElementType), targetIQ.Expression));
var newQueryable = targetIQ.Provider.CreateQuery(targetIQ.Expression);
IQueryable newQueryable = null;
if (_isParallelQuery)
newQueryable = targetIQ.Provider.CreateQuery((Expression)Expression.Call((Expression)null, typeof(EntityFrameworkQueryableExtensions).GetTypeInfo().GetDeclaredMethod(nameof(EntityFrameworkQueryableExtensions.AsNoTracking)).MakeGenericMethod(queryable.ElementType), targetIQ.Expression));
else
newQueryable = targetIQ.Provider.CreateQuery(targetIQ.Expression);
Source = newQueryable;
// return base.Visit(Expression.Constant(newQueryable));
return Expression.Constant(newQueryable);
@ -45,15 +50,16 @@ namespace ShardingCore.Core.Internal.Visitors
#endif
#if EFCORE5 || EFCORE6
internal class DbContextReplaceQueryableVisitor : ExpressionVisitor
{
private readonly DbContext _dbContext;
private readonly bool _isParallelQuery;
public IQueryable Source;
public DbContextReplaceQueryableVisitor(DbContext dbContext)
public DbContextReplaceQueryableVisitor(DbContext dbContext, bool isParallelQuery)
{
_dbContext = dbContext;
_isParallelQuery = isParallelQuery;
}
protected override Expression VisitExtension(Expression node)
@ -63,8 +69,11 @@ namespace ShardingCore.Core.Internal.Visitors
var dbContextDependencies = typeof(DbContext).GetTypePropertyValue(_dbContext, "DbContextDependencies") as IDbContextDependencies;
var targetIQ = (IQueryable)((IDbSetCache)_dbContext).GetOrAddSet(dbContextDependencies.SetSource, queryRootExpression.EntityType.ClrType);
//AsNoTracking
//(Expression)Expression.Call((Expression)null, typeof(EntityFrameworkQueryableExtensions).GetTypeInfo().GetDeclaredMethod("AsNoTracking").MakeGenericMethod(queryRootExpression.EntityType.ClrType), targetIQ.Expression)
var newQueryable = targetIQ.Provider.CreateQuery(targetIQ.Expression);
IQueryable newQueryable = null;
if (_isParallelQuery)
newQueryable = targetIQ.Provider.CreateQuery((Expression)Expression.Call((Expression)null, typeof(EntityFrameworkQueryableExtensions).GetTypeInfo().GetDeclaredMethod(nameof(EntityFrameworkQueryableExtensions.AsNoTracking)).MakeGenericMethod(queryRootExpression.EntityType.ClrType), targetIQ.Expression));
else
newQueryable = targetIQ.Provider.CreateQuery(targetIQ.Expression);
Source = newQueryable;
//如何替换ef5的set
var replaceQueryRoot = new ReplaceSingleQueryRootExpressionVisitor();