【问题标题】:Hangfire causes Timeout expired exception when executing SQL Code to optimzie database - ASP.NET Core执行 SQL 代码以优化数据库时,Hangfire 导致超时过期异常 - ASP.NET Core
【发布时间】:2019-06-13 21:31:06
【问题描述】:

我将以下代码设置为计划任务:

public class OptimizeDatabase : IJob {

    #region Constructor
    public OptimizeDatabase(DataContext dataContext) {
        DbContext = dataContext;
    }
    #endregion

    #region Fields
    private readonly DataContext DbContext;
    #endregion

    #region Methods
    public async Task Execute() {
        Stopwatch stopWatch = new Stopwatch();
        stopWatch.Start();
        string result = "Ok";
        try {
            // Rebuild Indexes
            DbContext.Database.ExecuteSqlCommand("EXEC sp_MSforeachtable \"ALTER INDEX ALL ON ? REBUILD WITH (ONLINE=OFF)\"");
            // Update Statistics
            DbContext.Database.ExecuteSqlCommand("EXEC sp_updatestats;");
        }
        catch (Exception ex) {
            result = ex.Message + Environment.NewLine + ex.StackTrace;
        }
        stopWatch.Stop();
        DbContext.TaskLogs.Add(new TaskLog {
            Date = DateTime.Now,
            ElapsedSeconds = stopWatch.Elapsed.TotalSeconds,
            Result = result,
            Task = "Optimize Database"
        });
        await DbContext.SaveChangesAsync();
    }
    #endregion
}

它被配置为在 Startup.cs 中运行

RecurringJob.AddOrUpdate<OptimizeDatabase>(x => x.Execute(), Cron.Daily(10));

所有其他计划任务执行都没有问题,但是,这个总是抛出以下错误:

超时。在完成之前超时时间已过 操作或服务器没有响应。在 System.Data.SqlClient.SqlConnection.OnError(SqlException 异常, Boolean breakConnection, Action`1 wrapCloseInAction)

感谢任何想法或见解。

【问题讨论】:

  • 您正在运行的查询未使用默认的 CommandTimeout 值完成,如果您无法进一步优化查询,可以将 CommandTimeout 增加到更高的数字。

标签: asp.net sql-server asp.net-core hangfire


【解决方案1】:

超时问题是因为其中一个查询花费的时间比它应该的要长。

据我所知,.Net 中有 2 个超时,连接超时 (ConnectionTimeout Property) 和命令超时 (CommandTimeout Property)。两者的超时默认时间都是30秒。

我建议你:

  • 在 SQL Management Studio 中运行查询,以了解按代码所示顺序运行两个查询所需的时间。
  • 设置连接超时和命令超时时从上一次在 SQL Management Studio 运行的秒数。如果超时继续出现,请尝试为每次超时增加更多时间,每次超时增加 30 秒,直到找到执行查询所需的最短时间。找到后,为确保每次超时增加 30 秒。

获取您的部分代码,更改将类似于:

try {
        // Change CommandTimeout
        DbContext.Database.CommandTimeout = 120;
        // Rebuild Indexes
        DbContext.Database.ExecuteSqlCommand("EXEC sp_MSforeachtable \"ALTER INDEX ALL ON ? REBUILD WITH (ONLINE=OFF)\"");
        // Update Statistics
        DbContext.Database.ExecuteSqlCommand("EXEC sp_updatestats;");
    }
    catch (Exception ex) {
        result = ex.Message + Environment.NewLine + ex.StackTrace;
    }

你可以看看这篇文章,它解释了可能导致超时的好场景https://stackoverflow.com/a/8603111/2654879

【讨论】:

    【解决方案2】:

    您的问题的答案很简单。您正在尝试重建数据库中所有表的索引并通过 hangfire 作业执行此语句。 Hangfire 作业现在尝试为自己的表重建索引,这会造成死锁。

    您必须一个接一个地为所有表显式重建索引,例如:

     ALTER INDEX ALL ON [dbo].[A] REBUILD;
     ALTER INDEX ALL ON [dbo].[B] REBUILD;
    

    【讨论】:

      猜你喜欢
      • 2014-03-08
      • 1970-01-01
      • 2012-04-29
      • 2018-09-27
      • 2012-08-26
      • 2023-03-15
      • 1970-01-01
      • 1970-01-01
      • 2022-12-21
      相关资源
      最近更新 更多