在实体框架中设置提取大小



我正在转换 ado.net 代码以使用 EF。在我的 ado.net 代码中,我设置了dataReader.FetchSize = command.RowSize * 1000,这大大提高了默认提取大小的性能。当我将代码转换为 EF 时,性能与未指定提取大小的 ado.net 代码相当,即在大型记录上它非常慢。

有什么方法可以指定用于在EF中检索记录的提取大小吗?

使用实体框架时,可以在注册表或 .NET 配置文件中设置 FetchSize ODP.NET。这将标准化所有 ODP.NET 实例(在注册表的情况下)或整个应用程序(在app/web.config的情况下)的FetchSize。

http://docs.oracle.com/cd/E48297_01/doc/win.121/e41125/featConfig.htm

克里斯蒂安·谢伊

神谕

我遇到了类似的问题,但不想更改整体 FetchSize,而是想更改每个查询的 FetchSize。

这是我想出的解决方案,也许这对某人有所帮助。它基本上使用CallContext将参数传递给DbInterceptor。侦听器将覆盖查询命令所需的属性。

线程安全,支持嵌套作用域。

这还可用于修改通过实体框架查询为定义的范围执行的命令的其他属性。

用法:

using (var context = new MyDbContext())
{
    using (new OracleCommandContext(fetchSize: 1024 * 128))
    {
        // your query here
    }
}

要覆盖的属性:

public class OracleCommandProperties
{
    public long FetchSize { get; set; } = 524288; // oracle default value
}

调用上下文:

public class OracleCommandContext : IDisposable
{
    private static readonly object sync = new object();
    private readonly OracleCommandProperties previousCommandProperties;
    private bool isDisposed;
    static OracleCommandContext()
    {
        DbInterception.Add(new OracleCommandInterceptor());
    }
    public OracleCommandContext(long fetchSize)
    {
        lock (sync)
        {
            var commandProperties = new OracleCommandProperties();
            if (TryGetProperties(out var previousProperties))
            {
                // when using nested OracleCommandContext, escalate the properties
                previousCommandProperties = previousProperties;
                commandProperties.FetchSize = Math.Max(previousProperties.FetchSize, fetchSize);
            }
            else
            {
                commandProperties.FetchSize = fetchSize;
            }
            CallContext.LogicalSetData(nameof(OracleCommandProperties), commandProperties);
        }
    }
    public void Dispose()
    {
        Dispose(true);
        GC.SuppressFinalize(this);
    }
    ~OracleCommandContext()
    {
        Dispose(false);
    }
    private void Dispose(bool disposing)
    {
        if (disposing)
        {
            if (!isDisposed)
            {
                lock (sync)
                {
                    CallContext.LogicalSetData(nameof(OracleCommandProperties), previousCommandProperties);
                }
                isDisposed = true;
            }
        }
    }
    public static bool TryGetProperties(out OracleCommandProperties properties)
    {
        lock(sync)
        {
            if (CallContext.LogicalGetData(nameof(OracleCommandProperties)) is OracleCommandProperties oracleReaderProperties)
            {
                properties = oracleReaderProperties;
                return true;
            }
            properties = null;
            return false;
        }
    }
}

执行实际工作的拦截器:

public class OracleCommandInterceptor : IDbCommandInterceptor
{
    public void NonQueryExecuted(DbCommand command, DbCommandInterceptionContext<int> interceptionContext)
    {
    }
    public void NonQueryExecuting(DbCommand command, DbCommandInterceptionContext<int> interceptionContext)
    {
        AdjustCommand(command);
    }
    public void ReaderExecuted(DbCommand command, DbCommandInterceptionContext<DbDataReader> interceptionContext)
    {
    }
    public void ReaderExecuting(DbCommand command, DbCommandInterceptionContext<DbDataReader> interceptionContext)
    {
        AdjustCommand(command);
    }
    public void ScalarExecuted(DbCommand command, DbCommandInterceptionContext<object> interceptionContext)
    {
    }
    public void ScalarExecuting(DbCommand command, DbCommandInterceptionContext<object> interceptionContext)
    {
        AdjustCommand(command);
    }
    private static void AdjustCommand(DbCommand command)
    {
        if (command is OracleCommand oracleCommand)
        {
            if (OracleCommandContext.TryGetProperties(out var properties))
            {
                oracleCommand.FetchSize = properties.FetchSize;
            }
        }
    }
}

最新更新