我使用下面的扩展函数来更新数据与EF Core与EFCore.BulkExtensions,但问题是这个函数的执行,当我试图插入200万记录是大约17分钟,最近它抛出了这个异常

无法为数据库"tempdb"中的对象"dbo. SORT临时运行存储:140737501921280"分配空间,因为"PRIMARY"文件组已满.通过删除不需要的文件、删除文件组中的对象、向文件组中添加其他文件或为文件组中的现有文件设置自动增长来创建磁盘空间.\ r\n由于"ACTIVE_TRANSACTION",数据库"temPDB"的事务日志(log)已满,并且holdup lsn为(41:136:347)

我可以看到"C"分区的存储量正在减少,当我执行这个函数:

enter image description here

当我重新启动SQL Server时,可用空间变为大约30 GB,我try 使用多线程(并行)与插入没有注意到的时间变化,所以你有什么建议或有任何问题在这里显示的代码.

Note: for循环不会花费太多时间,即使它是200万条记录.

public static async Task<OperationResultDto> AddOrUpdateBulkByTransactionAsync<TEntity>(this DbContext _myDatabaseContext, List<TEntity> data) where TEntity : class
{
    using (var transaction = await _myDatabaseContext.Database.BeginTransactionAsync())
    {
        try
        {
            _myDatabaseContext.Database.SetCommandTimeout(0);

            var currentTime = DateTime.Now;

            // Disable change tracking
            _myDatabaseContext.ChangeTracker.AutoDetectChangesEnabled = false;

            // Set CreatedDate and UpdatedDate for each entity
            foreach (var entity in data)
            {
                var createdDateProperty = entity.GetType().GetProperty("CreatedDate");

                if (createdDateProperty != null && (createdDateProperty.GetValue(entity) == null || createdDateProperty.GetValue(entity).Equals(DateTime.MinValue)))
                {
                    // Set CreatedDate only if it's not already set
                    createdDateProperty.SetValue(entity, currentTime);
                }

                var updatedDateProperty = entity.GetType().GetProperty("UpdatedDate");

                if (updatedDateProperty != null)
                {
                    updatedDateProperty.SetValue(entity, currentTime);
                }
            }

            // Bulk insert or update
            var updateByProperties = GetUpdateByProperties<TEntity>();

            var bulkConfig = new BulkConfig()
            {
                UpdateByProperties = updateByProperties,
                CalculateStats = true,
                SetOutputIdentity = false
            };

            // Batch size for processing
            int batchSize = 50000;

            for (int i = 0; i < data.Count; i += batchSize)
            {
                var batch = data.Skip(i).Take(batchSize).ToList();
                await _myDatabaseContext.BulkInsertOrUpdateAsync(batch, bulkConfig);
            }

            // Commit the transaction if everything succeeds
            await transaction.CommitAsync();

            return new OperationResultDto
            {
                OperationResult = bulkConfig.StatsInfo
            };
        }
        catch (Exception ex)
        {
            // Handle exceptions and roll back the transaction if something goes wrong
            transaction.Rollback();
            return new OperationResultDto
            {
                Error = new ErrorDto
                {
                    Details = ex.Message + ex.InnerException?.Message
                }
            };
        }
        finally
        {
            // Re-enable change tracking
            _myDatabaseContext.ChangeTracker.AutoDetectChangesEnabled = true;
        }
    }
}

推荐答案

看起来手工操作会产生更多的启动成本.此外,您使用的是CalculateStats = true,这意味着每次运行都将逐点重新计算统计数据.

SqlBulkCopy,这是BulkExtension在引擎盖下使用的,内置了NTFS,你可以在批量配置中使用它.你不需要自己批.然后,它将在最后计算统计数据(或者你可以关闭它).

此外,显式事务意味着数据库事务日志(log)以及tempdb数据库中的任何行和行版本控制,在提交之前不能被清除.您可能想要一个干净的回滚,但它确实有代价.如果你真的需要它,只需将配置中的批处理大小设置为0,就可以得到一个大的内部事务.

所以你所需要的就是:

var bulkConfig = new BulkConfig()
{
    UpdateByProperties = updateByProperties,
    CalculateStats = true,
    SetOutputIdentity = false,
    BatchSize = 50000
};
await _myDatabaseContext.BulkInsertOrUpdateAsync(data, bulkConfig);

也可以考虑使用BulkInsertAsync而不是BulkInsertOrUpdateAsync,因为它可以直接插入到表中,而不是通过临时表和MERGE.

Csharp相关问答推荐

Rx.Net -当关闭序列被触发时如何聚合消息并发出中间输出?

为什么.Equals(SS,StringComparison. ClientCultureIgnoreCase)在Net 4.8和6.0之间不同?

当打印一行x个项目时,如何打印最后一行项目?

将委托传递到serviceccollection c#web API

如何在Reflection. Emit中使用具有运行时定义的类型参数的泛型类型

如果属性名为xyz,我需要使用System.Text.Json修改字符串类型的值""<>

Polly v8—使用PredicateBuilder重试特定的状态代码

Polly使用泛型重试和重试包装函数

WeakReference未被垃圾收集

Amazon SP-API确认发货不设置&Quot;递送服务

每个http请求需要60秒,为什么?

反序列化私有成员

CA1508:';NULL=>;TRUE;始终为';TRUE';.移除或重构条件(S)以避免死代码

将类移动到新命名空间后更新RavenDB Raven-Clr-Type

当我没有此令牌时,为什么语法报告EOF错误?

自定义列表按字符串的部分排序

对于PowerShell中的ConvertTo-SecureString方法,Microsoft如何将初始化向量添加到AES加密中的安全字符串?

如何读取TagHelper属性的文本值?

如果所有";async任务方法()";调用都返回Task.FromResult()-是否同步执行?

不寻常的C#语法