You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Azure容器应用中EF Core查询执行超时问题求助

问题:Azure容器应用对接本地SQL Server时EF Core查询超时

在Azure容器应用对接本地SQL Server场景下,EF Core部分查询执行超时,相同代码在本地Docker环境运行正常。仅返回少量列的查询可正常执行,返回约10列及以上时触发超时。

超时查询代码

IQueryable<Disbursement> response = _dataContext.Disbursements
    .Where(w => w.DisbursementDate <= disbursementDate && !w.DeletedFlag && !w.Paid && w.MethodId == methodId && w.AccountId == accountId)
    .OrderByDescending(o => o.CreatedOnDateUtc);

var result = response.Skip((page - 1) * pageSize)
    .Take(pageSize)
    .ToList();

正常查询示例

IQueryable<AccountBillingModel> response = _dataContext.Disbursements.Where(w => w.DisbursementDate <= disbursementDate && !w.DeletedFlag && !w.Paid && w.MethodId == methodId)
    .Select(s => s.AccountId)
    .Distinct()
    .Select(s => new AccountBillingModel
    {
        AccountId = s
    });

return await response.ToListAsync();

Disbursement模型定义

public class Disbursement
{
    public Guid Id { get; set; }
    public Guid TransactionId { get; set; }
    public Guid AccountId { get; set; }
    public Guid MethodId { get; set; }
    public string ExternalItemId { get; set; } = string.Empty;
    public string Description { get; set; } = string.Empty;
    public int Quantity { get; set; }
    public double PriceExcluding { get; set; }
    public bool Paid { get; set; }
    public DateTime DisbursementDate { get; set; }
    public DateTime? DisbursementRunDate { get; set; }
    public DateTime? AmendedOnDateUtc { get; set; }
    public bool DeletedFlag { get; set; } = false;
    public DateTime CreatedOnDateUtc { get; set; } = DateTime.UtcNow;
}

DbContext定义

public class DataContext : DbContext
{
    public DataContext(DbContextOptions options) : base(options) { }
    public DbSet<Disbursement> Disbursements { get; set; }
}

已尝试的排查动作

  • 切换EF Core 6/8、.NET Core 6/8版本
  • 将异步调用(如ToListAsync())改为同步ToList()
    以上操作均未解决问题

Disbursements表结构

CREATE TABLE [dbo].[Disbursements] 
(
    [Id]                UNIQUEIDENTIFIER CONSTRAINT [DF_Disbursements_Id] DEFAULT (newid()) NOT NULL,
    [AccountId]         UNIQUEIDENTIFIER NOT NULL,
    [MethodId]          UNIQUEIDENTIFIER NOT NULL,
    [ExternalItemId]    NVARCHAR(50)     NOT NULL,
    [Description]       NVARCHAR(150)    NOT NULL,
    [Quantity]          INT              NOT NULL,
    [PriceExcluding]    FLOAT (53)       NOT NULL,
    [DisbursementDate]  DATETIME         NOT NULL,
    [Paid]              BIT              CONSTRAINT [DF_Disbursements_Paid] DEFAULT ((0)) NOT NULL,
    [AmendedOnDateUtc]  DATETIME         NULL,
    [CreatedOnDateUtc]  DATETIME         NOT NULL,
    [DeletedFlag]       BIT              CONSTRAINT [DF_Disbursements_DeletedFlag] DEFAULT ((0)) NOT NULL,
    [DisbursementRunDate] DATETIME NULL, 

    CONSTRAINT [PK_Disbursements] PRIMARY KEY CLUSTERED ([Id] ASC)
);

异常堆栈信息

An exception occurred while iterating over the results of a query for context type '****'.
Microsoft.Data.SqlClient.SqlException (0x80131904): Execution Timeout Expired.  The timeout period elapsed prior to completion of the operation or the server is not responding.
 ---> System.ComponentModel.Win32Exception (258): Unknown error 258
   
   at Microsoft.Data.SqlClient.SqlInternalConnection.OnError(SqlException exception, Boolean breakConnection, Action`1 wrapCloseInAction)
   
   at Microsoft.Data.SqlClient.TdsParser.ThrowExceptionAndWarning(TdsParserStateObject stateObj, Boolean callerHasConnectionLock, Boolean asyncClose)
   
   at Microsoft.Data.SqlClient.TdsParserStateObject.ThrowExceptionAndWarning(Boolean callerHasConnectionLock, Boolean asyncClose)
   
   at Microsoft.Data.SqlClient.TdsParserStateObject.ReadSniError(TdsParserStateObject stateObj, UInt32 error)
   
   at Microsoft.Data.SqlClient.TdsParserStateObject.ReadSniSyncOverAsync()
   
   at Microsoft.Data.SqlClient.TdsParserStateObject.TryReadNetworkPacket()
   
   at Microsoft.Data.SqlClient.TdsParserStateObject.TryPrepareBuffer()
   
   at Microsoft.Data.SqlClient.TdsParserStateObject.TryReadByte(Byte& value)
   
   at Microsoft.Data.SqlClient.TdsParser.TryRun(RunBehavior runBehavior, SqlCommand cmdHandler, SqlDataReader dataStream, BulkCopySimpleResultSet bulkCopyHandler, TdsParserStateObject stateObj, Boolean& dataReady)
   
   at Microsoft.Data.SqlClient.SqlDataReader.TryConsumeMetaData()
   
   at Microsoft.Data.SqlClient.SqlDataReader.get_MetaData()
   
   at Microsoft.Data.SqlClient.SqlCommand.FinishExecuteReader(SqlDataReader ds, RunBehavior runBehavior, String resetOptionsString, Boolean isInternal, Boolean forDescribeParameterEncryption, Boolean shouldCacheForAlwaysEncrypted)
   
   at Microsoft.Data.SqlClient.SqlCommand.RunExecuteReaderTds(CommandBehavior cmdBehavior, RunBehavior runBehavior, Boolean returnStream, Boolean isAsync, Int32 timeout, Task& task, Boolean asyncWrite, Boolean inRetry, SqlDataReader ds, Boolean describeParameterEncryptionRequest)
   
   at Microsoft.Data.SqlClient.SqlCommand.RunExecuteReader(CommandBehavior cmdBehavior, RunBehavior runBehavior, Boolean returnStream, TaskCompletionSource`1 completion, Int32 timeout, Task& task, Boolean& usedCache, Boolean asyncWrite, Boolean inRetry, String method)
   
   at Microsoft.Data.SqlClient.SqlCommand.RunExecuteReader(CommandBehavior cmdBehavior, RunBehavior runBehavior, Boolean returnStream, String method)
   
   at Microsoft.Data.SqlClient.SqlCommand.ExecuteReader(CommandBehavior behavior)
   
   at Microsoft.Data.SqlClient.SqlCommand.ExecuteDbDataReader(CommandBehavior behavior)
   
   at Microsoft.EntityFrameworkCore.Storage.RelationalCommand.ExecuteReader(RelationalCommandParameterObject parameterObject)
   
   at Microsoft.EntityFrameworkCore.Query.Internal.SingleQueryingEnumerable`1.Enumerator.InitializeReader(Enumerator enumerator)
   
   at Microsoft.EntityFrameworkCore.Query.Internal.SingleQueryingEnumerable`1.Enumerator.<>c.<MoveNext>b__19_0(DbContext _, Enumerator enumerator)
   
   at Microsoft.EntityFrameworkCore.SqlServer.Storage.Internal.SqlServerExecutionStrategy.Execute[TState,TResult](TState state, Func`3 operation, Func`3 verifySucceeded)
   
   at Microsoft.EntityFrameworkCore.Query.Internal.SingleQueryingEnumerable`1.Enumerator.MoveNext()
ClientConnectionId:038757a9-2247-477d-98c5-31eacfa8d39d
Error Number:-2,State:0,Class:11",
  "Exception": "Microsoft.Data.SqlClient.SqlException (0x80131904): Execution Timeout Expired.  The timeout period elapsed prior to completion of the operation or the server is not responding.
 ---> System.ComponentModel.Win32Exception (258): Unknown error 258
   
   at Microsoft.Data.SqlClient.SqlInternalConnection.OnError(SqlException exception, Boolean breakConnection, Action`1 wrapCloseInAction)
   
   at Microsoft.Data.SqlClient.TdsParser.ThrowExceptionAndWarning(TdsParserStateObject stateObj, Boolean callerHasConnectionLock, Boolean asyncClose)
   
   at Microsoft.Data.SqlClient.TdsParserStateObject.ThrowExceptionAndWarning(Boolean callerHasConnectionLock, Boolean asyncClose)
   
   at Microsoft.Data.SqlClient.TdsParserStateObject.ReadSniError(TdsParserStateObject stateObj, UInt32 error)
   
   at Microsoft.Data.SqlClient.TdsParserStateObject.ReadSniSyncOverAsync()
   
   at Microsoft.Data.SqlClient.TdsParserStateObject.TryReadNetworkPacket()
   
   at Microsoft.Data.SqlClient.TdsParserStateObject.TryPrepareBuffer()
   
   at Microsoft.Data.SqlClient.TdsParserStateObject.TryReadByte(Byte& value)
   
   at Microsoft.Data.SqlClient.TdsParser.TryRun(RunBehavior runBehavior, SqlCommand cmdHandler, SqlDataReader dataStream, BulkCopySimpleResultSet bulkCopyHandler, TdsParserStateObject stateObj, Boolean& dataReady)
   
   at Microsoft.Data.SqlClient.SqlDataReader.TryConsumeMetaData()
   
   at Microsoft.Data.SqlClient.SqlDataReader.get_MetaData()
   
   at Microsoft.Data.SqlClient.SqlCommand.FinishExecuteReader(SqlDataReader ds, RunBehavior runBehavior, String resetOptionsString, Boolean isInternal, Boolean forDescribeParameterEncryption, Boolean shouldCacheForAlwaysEncrypted)
   
   at Microsoft.Data.SqlClient.SqlCommand.RunExecuteReaderTds(CommandBehavior cmdBehavior, RunBehavior runBehavior, Boolean returnStream, Boolean isAsync, Int32 timeout, Task& task, Boolean asyncWrite, Boolean inRetry, SqlDataReader ds, Boolean describeParameterEncryptionRequest)
   
   at Microsoft.Data.SqlClient.SqlCommand.RunExecuteReader(CommandBehavior cmdBehavior, RunBehavior runBehavior, Boolean returnStream, TaskCompletionSource`1 completion, Int32 timeout, Task& task, Boolean& usedCache, Boolean asyncWrite, Boolean inRetry, String method)
   
   at Microsoft.Data.SqlClient.SqlCommand.RunExecuteReader(CommandBehavior cmdBehavior, RunBehavior runBehavior, Boolean returnStream, String method)
   
   at Microsoft.Data.SqlClient.SqlCommand.ExecuteReader(CommandBehavior behavior)
   
   at Microsoft.Data.SqlClient.SqlCommand.ExecuteDbDataReader(CommandBehavior behavior)
   
   at Microsoft.EntityFrameworkCore.Storage.RelationalCommand.ExecuteReader(RelationalCommandParameterObject parameterObject)
   
   at Microsoft.EntityFrameworkCore.Query.Internal.SingleQueryingEnumerable`1.Enumerator.InitializeReader(Enumerator enumerator)
   
   at Microsoft.EntityFrameworkCore.Query.Internal.SingleQueryingEnumerable`1.Enumerator.<>c.<MoveNext>b__19_0(DbContext _, Enumerator enumerator)
   
   at Microsoft.EntityFrameworkCore.SqlServer.Storage.Internal.SqlServerExecutionStrategy.Execute[TState,TResult](TState state, Func`3 operation, Func`3 verifySucceeded)
   
   at Microsoft.EntityFrameworkCore.Query.Internal.SingleQueryingEnumerable`1.Enumerator.MoveNext()
ClientConnectionId:038757a9-2247-477d-98c5-31eacfa8d39d
Error Number:-2,State:0,Class:11

服务器跟踪结果

  • 超时查询仅显示登录,一段时间后登出;正常查询则是登录、执行查询后立即登出。

超时查询生成的SQL示例

SELECT [t0].[id],
       [t0].[accountid],
       [t0].[amendedondateutc],
       [t0].[billrundate],
       [t0].[billingdate],
       [t0].[contractid],
       [t0].[corrolationid],
       [t0].[createdondateutc],
       [t0].[creditnotenumber],
       [t0].[deletedflag],
       [t0].[description],
       [t0].[invoicenumber],
       [t0].[invoicesent],
       [t0].[methodid],
       [t0].[ordernumber],
       [t0].[paid],
       [t0].[partyid],
       [t0].[status],
       [t0].[tenantid],
       [t0].[tokenid],
       [t1].[id],
       [t1].[amendedondateutc],
       [t1].[createdondateutc],
       [t1].[deletedflag],
       [t1].[description],
       [t1].[externalitemid],
       [t1].[invoicedescription],
       [t1].[note],
       [t1].[priceexcluding],
       [t1].[quantity],
       [t1].[transactiondate],
       [t1].[transactionid]
FROM   (SELECT TOP(1) [t].[id],
                      [t].[accountid],
                      [t].[amendedondateutc],
                      [t].[billrundate],
                      [t].[billingdate],
                      [t].[contractid],
                      [t].[corrolationid],
                      [t].[createdondateutc],
                      [t].[creditnotenumber],
                      [t].[deletedflag],
                      [t].[description],
                      [t].[invoicenumber],
                      [t].[invoicesent],
                      [t].[methodid],
                      [t].[ordernumber],
                      [t].[paid],
                      [t].[partyid],
                      [t].[status],
                      [t].[tenantid],
                      [t].[tokenid]
        FROM   [dbo].[transactions] AS [t]
        WHERE  [t].[id] = '*****') AS [t0]
       LEFT JOIN [dbo].[transactionitems] AS [t1]
              ON [t0].[id] = [t1].[transactionid]
ORDER  BY [t0].[id] 

排查与解决建议

1. 网络层面排查

本地Docker正常但Azure容器应用异常,优先排查跨网络传输问题:

  • 测试Azure容器应用到SQL Server的大数据包传输是否正常,可通过ping -l 1472 <SQL Server IP>验证MTU适配情况
  • 在SQL连接字符串中添加Packet Size=4096,减小单数据包体积,避免传输超时
  • 检查本地SQL Server防火墙是否限制了Azure来源的连接,或存在带宽、连接数阈值限制

2. 索引与查询优化

针对超时查询的过滤、排序逻辑创建覆盖索引,减少数据扫描和回表:

CREATE NONCLUSTERED INDEX IX_Disbursements_FilterSort ON dbo.Disbursements
(
    MethodId,
    AccountId,
    DisbursementDate,
    CreatedOnDateUtc DESC
)
INCLUDE 
(
    DeletedFlag,
    Paid,
    Id, TransactionId, ExternalItemId, Description, Quantity, PriceExcluding, DisbursementRunDate, AmendedOnDateUtc
);
  • 执行SET SHOWPLAN_XML ON;后运行超时查询,确认索引是否被正确调用

3. EF Core查询调整

拆分分页查询逻辑,先获取主键再查询详情,减少单次传输的数据量:

var ids = _dataContext.Disbursements
    .Where(w => w.DisbursementDate <= disbursementDate && !w.DeletedFlag && !w.Paid && w.MethodId == methodId && w.AccountId == accountId)
    .OrderByDescending(o => o.CreatedOnDateUtc)
    .Skip((page - 1) * pageSize)
    .Take(pageSize)
    .Select(d => d.Id)
    .ToList();

var result = _dataContext.Disbursements
    .Where(d => ids.Contains(d.Id))
    .ToList();

4. SQL Server配置检查

  • 执行sp_configure 'remote query timeout', 0; RECONFIGURE;临时关闭远程查询超时限制,验证是否为配置导致
  • 查看SQL Server的CPU、内存使用率,排除服务器资源瓶颈

内容的提问来源于stack exchange,提问作者Armand

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.30 00:58:09