添加针对并发查询条件下使用asnotracking查询提高性能
This commit is contained in:
parent
e61e50693c
commit
7a302b8597
|
@ -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");
|
||||
|
|
|
@ -49,7 +49,8 @@ namespace ShardingCore.Core.EntityMetadatas
|
|||
return this;
|
||||
}
|
||||
/// <summary>
|
||||
/// 是否启动建表
|
||||
/// 是否启动的时候创建表,仅在启动时判断该属性,如果你是按时间分表的那么这个属性将不会在特定时间创建对应的表信息需要手动进行表创建和添加
|
||||
/// 当然您也可以使用系统默认的时间路由,通过重写AutoCreateByTime方法重写返回true来保证sharding_core开启定时任务并且已经集成自动创建表和库
|
||||
/// </summary>
|
||||
/// <param name="autoCreate"></param>
|
||||
/// <returns></returns>
|
||||
|
|
|
@ -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; }
|
||||
|
||||
|
|
|
@ -23,20 +23,11 @@ namespace ShardingCore.DbContexts
|
|||
{
|
||||
var routeTail=shardingDbContextOptions.RouteTail;
|
||||
|
||||
var dbContext = _shardingDbContextCreatorConfig.Creator(shardingDbContextOptions);
|
||||
var dbContext = _shardingDbContextCreatorConfig.Creator(shardingDbContextOptions);
|
||||
if (dbContext is IShardingTableDbContext shardingTableDbContext)
|
||||
{
|
||||
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;
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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
|
||||
;
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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返回-1,y返回1不进行比较
|
||||
/// </summary>
|
||||
/// <param name="x"></param>
|
||||
/// <param name="y"></param>
|
||||
/// <returns></returns>
|
||||
public int Compare(string? x, string? y)
|
||||
{
|
||||
if (_defaultTail.Equals(x))
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -215,7 +215,7 @@ namespace ShardingCore.Sharding
|
|||
/// 是否使用并行查询
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
private bool IsParallelQuery()
|
||||
public bool IsParallelQuery()
|
||||
{
|
||||
return !_shardingConfigOption.AutoTrackEntity|| IsCrossQuery() || IsUseReadWriteSeparation();
|
||||
}
|
||||
|
|
|
@ -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,11 +34,14 @@ 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);
|
||||
return Expression.Constant(newQueryable);
|
||||
}
|
||||
|
||||
return base.VisitConstant(node);
|
||||
|
@ -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)
|
||||
|
@ -61,10 +67,13 @@ namespace ShardingCore.Core.Internal.Visitors
|
|||
if (node is QueryRootExpression queryRootExpression)
|
||||
{
|
||||
var dbContextDependencies = typeof(DbContext).GetTypePropertyValue(_dbContext, "DbContextDependencies") as IDbContextDependencies;
|
||||
var targetIQ = (IQueryable) ((IDbSetCache) _dbContext).GetOrAddSet(dbContextDependencies.SetSource, queryRootExpression.EntityType.ClrType);
|
||||
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();
|
||||
|
|
Loading…
Reference in New Issue