我正在制作一个文件夹/文本文件阅读器。获取的数据应该推送到SQL服务器。然而,它真的,真的......慢。
真的很慢=>
需要插入的数据:
2.73 GB(2,938,952,122字节)
遍布
78,995个文件,5,908个文件夹
文件夹结构为
文件夹(顶级)
我一直在阅读它们3天或smth
另外因为文件包含很多重复值,我认为它也很慢
我认为正在发生的原因:
嵌套的foreach
源代码:
static void leesTxt(string rapport, string TreinNaam)
{
foreach (string textFilePath in Directory.EnumerateFiles(rapport, "*.txt"))
{
string textname = Path.GetFileName(textFilePath);
textname = textname.Substring(0, textname.Length - 4);
List<string> variablen = new List<string>();
using (StreamReader r = new StreamReader(textFilePath))
{
for (int x = 0; x <= 10; x++)
r.ReadLine();
string output;
while (true)
{
output = r.ReadLine();
if (output == null)
break;
if (Regex.IsMatch(output, @"^\d"))
{
variablen.Clear();
string[] info = output.Split(' ');
int kolom = 6;
datum = info[0];
string[] datumTijdelijk = datum.Split(new[] { '/' });
try
{
datum = string.Format("{2}/{1}/{0}",
}
catch
{
datum = "0002/02/02";
}
try
{
tijd = info[1];
}
catch
{
Debug.WriteLine(tijd);
tijd = "00:00:00.000";
}
try
{
foutcode = info[2];
absentOfPresent = info[4];
teller = info[5];
omschrijving = info[6];
}
catch
{
}
while (kolom < info.Count() - 1)
{
kolom++;
omschrijving = omschrijving + " " + info[kolom];
}
PushFoutenToSQLdb(datum, tijd, foutcode, textname, omschrijving, teller, absentOfPresent, TreinNaam);
}
if (output == string.Empty)
{
output = " ";
}
if (Char.IsLetter(output[0]))
{
if (variablen.Contains(output))
output = output + "*";
try
{
PushExtraInfoToSQLdb(output, datum, tijd, foutcode, textname, teller, absentOfPresent, omschrijving, TreinNaam);
}
catch (Exception ex)
{
}
variablen.Add(output);
}
}
}
static void PushExtraInfoToSQLdb(string waarde, string datum, string tijd, string foutcode, string module, string teller, string Mnemo, string omschrijving, string treinNaam)
{
myCommand = new SqlCommand("INSERT INTO [Events].[dbo].[ExtraInfo] (Value,FoutId) Values (@waarde,(SELECT FoutId from [Events].[dbo].[Fouten] WHERE Datum = @datum AND Time = @tijd AND FoutCode = @foutcode AND TreinId = (SELECT TreinId from [Events].[dbo].[Treinen] WHERE Name = @treinNaam)))", myConnection);
myCommand.Parameters.AddWithValue("@waarde", waarde);
myCommand.Parameters.AddWithValue("@datum", datum);
myCommand.Parameters.AddWithValue("@tijd", tijd);
myCommand.Parameters.AddWithValue("@foutcode", foutcode);
myCommand.Parameters.AddWithValue("@module", module);
myCommand.Parameters.AddWithValue("@teller", teller);
myCommand.Parameters.AddWithValue("@Mnemo", Mnemo);
myCommand.Parameters.AddWithValue("@omschrijving", omschrijving);
myCommand.Parameters.AddWithValue("@treinNaam", treinNaam);
try
{
myCommand.ExecuteNonQuery();
}
catch (Exception ex)
{
}
}
static void PushFoutenToSQLdb(string datum, string tijd, string foutcode, string module, string omschrijving, string teller, string absentPresent, string treinNaam)
{
myCommand = new SqlCommand("INSERT INTO [Events].[dbo].[Fouten] (Datum ,FoutCode, Omschrijving, Module,Time,Teller,Mnemo, TreinId) Values (@datum , @foutcode, @omschrijving, @module, @tijd, @teller, @absentPresent ,(SELECT TreinId from [Events].[dbo].[Treinen] WHERE Name = @treinNaam))", myConnection);
myCommand.Parameters.AddWithValue("@datum", datum);
myCommand.Parameters.AddWithValue("@tijd", tijd);
myCommand.Parameters.AddWithValue("@foutcode", foutcode);
myCommand.Parameters.AddWithValue("@module", module);
myCommand.Parameters.AddWithValue("@teller", teller);
myCommand.Parameters.AddWithValue("@omschrijving", omschrijving);
myCommand.Parameters.AddWithValue("@absentPresent", absentPresent);
myCommand.Parameters.AddWithValue("@treinNaam", treinNaam);
try
{
myCommand.ExecuteNonQuery();
}
catch (Exception ex)
{
}
}
答案 0 :(得分:1)
由于这些都是插入,并且正如每个人都指出的那样,逐行插入并不是一个好方法。查看SqlBulkCopy Class。这是为了直接从代码中将批量/批量插入编写到数据库,并考虑到性能。
摘自文档。
Microsoft SQL Server包含一个名为bcp的流行命令提示实用程序,用于将数据从一个表移动到另一个表,无论是在单个服务器上还是在服务器之间。 SqlBulkCopy类允许您编写提供类似功能的托管代码解决方案。 还有其他方法可以将数据加载到SQL Server表中(例如INSERT语句),但SqlBulkCopy比它们具有显着的性能优势。
您最好的方法(因为您的数据来自文本文件)可能是创建内存DataTable
,然后您可以在其中定义与数据库模式匹配的模式。然后,使用要插入的数据填充此表,并调用WriteToServer
方法并传入表。
由于SqlBulkCopy
仅支持每个实例写入1个表,因此您必须执行此操作2次,一次用于Fouten
表,一次用于ExtraInfo
表。当您在现有SELECT
语句中使用INSERT
语句时,您还必须提前获取一些信息,然后可以在传递它之前填充DataTable
。到SqlBulkCopy
实例。 SqlBulkCopy
也不能与Transactions
一起使用,因此在插入数据之前必须对数据进行整理,因为如果一条或多条记录存在验证错误,则无法轻松地将所有数据回滚。< / p>
TreinId
和值= Name
的字典,并使用DataReader
从现有数据中填充。Fouten
创建与Fouten
表架构TreinId
SqlBulkCopy
,上传您的数据DataReader
从现有(新)数据中填充此字典。 似乎有点浪费,也许有更好的方法来定义这个查找? ExtraInfo
表,并使用在步骤5中创建的词典将FK值返回到Fouten
SqlBulkCopy
,上传您的数据SqlBulkCopy
几乎不会产生影响。SELECT
语句的INSERT
部分中使用。