c# - 插入数百万条记录的最佳方法
问题描述
我正在使用 C# asp.net core、linQ 和 T-SQL 中的托管服务。
我需要在我的数据库中逐一插入记录。当然这不是一个快速的操作,但我在这个领域没有那么有经验,所以也许我做错了。这是我在经理中的代码:
public void StrategyMassive(string foldpathsave)
{
using (IServiceScope scope = _services.CreateScope())
{
List<string> filesreading = new List<string>();
VUContext _context = scope.ServiceProvider.GetRequiredService<VUContext>();
List<string> filesnumber = File.ReadAllLines(foldpathsave).ToList();
filesreading = filesnumber.ToList();
filesreading.RemoveRange(0, 2);
foreach (string singlefile in filesreading)
{
//INTERNAL DATA NORMALIZATION
_repository.ImportAdd(_context, newVUL, newC2, newC3, newDATE);
_repository.Save(_context);
}
}
}
这是我的存储库界面:
public void ImportAdd(VUContext _context, AVuTable newVUL, ACs2Table newC2, ACs3Table newC3, ADateTable newDATe)
{
_context.AVuTable.Add(newVU);
_context.ADateTable.Add(newDATE);
if (newC2 != null)
{
_context.ACs2Table.Add(newC2);
}
if (newC3 != null)
{
_context.ACs3Table.Add(newC3);
}
public void Save(VUContext _context)
{
_context.SaveChanges();
}
}
我知道这一切都很简单,那么我怎样才能加快这个插入的速度呢?
解决方案
以我的经验,SqlBulkCopy 是最快的方法。filesnumber 听起来用词不当,我怀疑您正在阅读经过一些规范化过程后要加载到 SQL Server 的分隔文件列表。如果您在最初将数据加载到临时文件后在服务器端进行规范化,那可能会更快。以下是分隔文件中的示例 SqlBulkCopy:
void Main()
{
Stopwatch sw = new Stopwatch();
sw.Start();
string sqlConnectionString = @"server=.\SQLExpress2012;Trusted_Connection=yes;Database=SampleDb";
string path = @"d:\temp\SampleTextFiles";
string fileName = @"combDoubledX.csv";
using (OleDbConnection cn = new OleDbConnection(
"Provider=Microsoft.ACE.OLEDB.12.0;Data Source="+path+
";Extended Properties=\"text;HDR=No;FMT=Delimited\";"))
using (SqlConnection scn = new SqlConnection( sqlConnectionString ))
{
OleDbCommand cmd = new OleDbCommand("select * from "+fileName, cn);
SqlBulkCopy sbc = new SqlBulkCopy(scn, SqlBulkCopyOptions.TableLock,null);
sbc.ColumnMappings.Add(0,"[Category]");
sbc.ColumnMappings.Add(1,"[Activity]");
sbc.ColumnMappings.Add(5,"[PersonId]");
sbc.ColumnMappings.Add(6,"[FirstName]");
sbc.ColumnMappings.Add(7,"[MidName]");
sbc.ColumnMappings.Add(8,"[LastName]");
sbc.ColumnMappings.Add(12,"[Email]");
cn.Open();
scn.Open();
SqlCommand createTemp = new SqlCommand();
createTemp.CommandText = @"if exists
(SELECT * FROM tempdb.sys.objects
WHERE object_id = OBJECT_ID(N'[tempdb]..[##PersonData]','U'))
BEGIN
drop table [##PersonData];
END
create table ##PersonData
(
[Id] int identity primary key,
[Category] varchar(50),
[Activity] varchar(50) default 'NullOlmasin',
[PersonId] varchar(50),
[FirstName] varchar(50),
[MidName] varchar(50),
[LastName] varchar(50),
[Email] varchar(50)
)
";
createTemp.Connection = scn;
createTemp.ExecuteNonQuery();
OleDbDataReader rdr = cmd.ExecuteReader();
sbc.NotifyAfter = 200000;
//sbc.BatchSize = 1000;
sbc.BulkCopyTimeout = 10000;
sbc.DestinationTableName = "##PersonData";
//sbc.EnableStreaming = true;
sbc.SqlRowsCopied += (sender,e) =>
{
Console.WriteLine("-- Copied {0} rows to {1}.[{2} milliseconds]",
e.RowsCopied,
((SqlBulkCopy)sender).DestinationTableName,
sw.ElapsedMilliseconds);
};
sbc.WriteToServer(rdr);
if (!rdr.IsClosed) { rdr.Close(); }
cn.Close();
scn.Close();
}
sw.Stop();
sw.Dump();
}
该文件中的几个示例行:
"Computer Labs","","LRC 302 Open Lab","","","10057380","Test","","Cetin","","5550123456","","cb@nowhere.com"
"Computer Labs","","LRC 302 Open Lab","","","123456789","John","","Doe","","5551234567","","jdoe@somewhere.com"
"Computer Labs","","LRC 302 Open Lab","","","012345678","Mary","","Doe","","5556666444","","mdoe@here.com"
您可以创建并运行 Tasks<> 的列表,从源中执行 SqlBulkCopy 读取(SqlBulkCopy 支持一系列读取器)。
推荐阅读
- ruby - 包括来自黄瓜内部 rspec 的共享示例
- database - 在 Firestore 中查询没有映射键的文档
- android - 无论如何要为整个应用程序而不是每个活动处理 onPause() 吗?
- c# - 无法转换 C# .Net Core 类型的对象
- python - 有没有一种简单的方法可以在 python 中模拟指针?
- reactjs - 将 React 客户端和 Rails API 推送到 Heroku,我在构建脚本中遇到错误
- junit4 - 使用“空手道”并行运行器时,Junit xml 报告不报告每个测试用例
- json - 使用 jq 解析 json 输出
- python - 使用 ASCII 将 13 添加到字符串(并保留其他字符,例如 !@> 和空格)
- pandas - 熊猫饼图:将类别捆绑为“其他”?