如果与临时表和更改跟踪结合使用,C# yield return 会导致问题吗?

Can C# yield return cause problems if used in combination with temp tables and Change Tracking?

我们正在使用 Microsoft SQL Server 2016 (SP2-CU12) (KB4536648) - 13.0.5698.0 (X64) 2020 年 2 月 15 日 01:47:30 版权所有 (c) Microsoft Corporation Standard Edition (64-位) Windows Server 2012 R2 Standard 6.3 (Build 9600: )

我们有一个 table 超过一百万行,其中有很多大字段(nvarchar(max)、bigint、uniqueidentifier)。我们在 table 上使用更改跟踪。此 table 由多线程 Web 应用程序和许多其他多线程应用程序访问。

现在在其中一个应用程序中,开发人员做了以下代码。

public IEnumerable<MyObject> GetRecords(long trackingKey)
{
  using(SqlConnection conn = new SqlConnection(_connectionString))
  {
    conn.Open();
    using(SqlCommand cmd = conn.CreateCommand())
    {
      StringBuilder builder = new StringBuilder();
      builder.Append("SELECT Columns INTO #TEMP FROM CHANGETABLE(CHANGES BigTable, @TrackingKey) AS CT JOIN BigTable t ON t.Key=CT.Key WHERE Conditions=@Conditions 

       SELECT * FROM #TEMP ");
      cmd.CommandText = builder.ToString();
      cmd.Parameters.Add...;

      using(SqlDataReader reader = cmd.ExecuteReader())
      {
        while(reader.Read())
        {
          yield return (MyObject)ExecuteMyReader(reader);
        }
      }
    }
  }
}

在“ExecuteMyReader”中,它们正在从 reader 中读取,并且对于该行,对另一个 table 执行第二个查询(平均执行大约需要 150 毫秒)。

查询 SQL 中的更改 table 查询似乎在从更改跟踪 table 中获取结果时锁定了 table。这就是为什么开发人员存储在执行最终 SELECT 查询之前会产生临时 table 的原因。 (为了尽量避免死锁。)

问题 #1:更改跟踪 table 的锁是否会在第二个 SELECT 查询完成时保持?或者一旦结果进入#Temp table?

就会发布

问题 #2:为 reader 执行 yield 与仅执行将所有内容都存储在变量中的经典方法相比有什么区别吗?例如,RAM 和#Temp table 是否会尽快发布?

问题#3:从多线程的角度来看,如果其他查询试图同时访问同一个table,是否有更好的方法来避免死锁? (有收益率,没有收益率的经典方法)

  1. 理论上,它应该只是 insert,但是用 into 创建临时 tables 会导致问题;也许尝试声明一个 table 变量而不是

  2. 迭代器的优点是它们不需要缓冲所有内容(它们可以作为开放序列使用)——因此它们可以更有效地使用 RAM,但是 side-effect那就是 command/connection 可能保持打开的时间更长;如果涉及锁,这可能会特别令人担忧,因为 DAL 代码不知道消费者在每一行之间需要多长时间

  3. 需要那么多隔离吗?也许考虑在较低的隔离级别查询它,并使用乐观并发(即rowversion)进行故障检测?