c#推进数据库的速度非常慢
我正在制作一个文件夹/文本文件阅读器。应将获取的数据推送到SQL server。然而,事情真的,真的。。慢点 真慢=> 需要插入的数据: 2.73 GB(2938952122字节) 蔓延 78995个文件,5908个文件夹 文件夹结构为 文件夹(顶级)c#推进数据库的速度非常慢,c#,sql,sql-server-2008,sqlcommand,C#,Sql,Sql Server 2008,Sqlcommand,我正在制作一个文件夹/文本文件阅读器。应将获取的数据推送到SQL server。然而,事情真的,真的。。慢点 真慢=> 需要插入的数据: 2.73 GB(2938952122字节) 蔓延 78995个文件,5908个文件夹 文件夹结构为 文件夹(顶级) 文件夹 文件夹 文本文件 更多文件夹->可能100个 文件夹 文件夹 文本文件 共60个文件夹 。。。 我已经读了大约3天了 此外,由于文件包含大量重复值,我认为速度也很慢 我认为发生这种情况的原因: 因为我有一个关
- 文件夹
- 文件夹
- 文本文件
- 更多文件夹->可能100个
- 文件夹
- 文本文件
- 。。。
- 有没有办法提高这种戏剧性的表现
- 我应该改用SQLbatchcopy吗?您甚至可以将其用于关系表,因为我看到的所有示例都只填充了一个表,而忽略了需要插入的外键(我的get是通过SQL db中的自动增量生成的)
- 有没有可能有另一种解决方案可以让这更容易
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)
{
}
}
static void leesTxt(字符串关系,字符串树)
{
foreach(Directory.EnumerateFiles(report,*.txt)中的字符串textFilePath)
{
字符串textname=Path.GetFileName(textFilePath);
textname=textname.Substring(0,textname.Length-4);
List variablen=新列表();
使用(StreamReader r=newstreamreader(textFilePath))
{
对于(int x=0;x,因为这些都是插入,而且正如每个人都指出的,逐行插入不是一个好方法。请查看。这是为了在考虑性能的情况下直接从代码将批/批量插入写入数据库而设计的
文件摘录
Microsoft SQL Server包含一个名为bcp的流行命令提示实用程序,用于将数据从一个表移动到另一个表,无论是在单个服务器上还是在服务器之间。SqlBulkCopy类允许您编写提供类似功能的托管代码解决方案。还有其他方法可以将数据加载到SQL Server表中(例如,插入语句),但SqlBulkCopy比它们具有显著的性能优势。
最好的方法(因为数据来自文本文件)可能是创建内存中的DataTable
,然后在其中定义与数据库架构匹配的架构。然后使用要插入的数据填充此表,并调用WriteToServer
方法并传入该表
由于SqlBulkCopy
仅支持每个实例写入1个表,因此您必须执行2次,一次用于Fouten
表,一次用于ExtraInfo
表。在使用现有INSE中的SELECT
语句时,您还必须先提取一些信息RT
语句,在将数据表传递给SqlBulkCopy
实例之前,可以使用该语句填充DataTable
。SqlBulkCopy
也不适用于事务
,因此在插入数据之前必须先对其进行sanatize处理,因为如果存在验证,则无法轻松回滚所有内容一条或多条记录上的错误
伪码
创建一个key=TreinId
和value=Name
的内存字典,并使用DataReader
从现有数据填充它
为Fouten
创建与Fouten
表架构匹配的数据表
使用文本文件中的数据填充表格,并使用步骤1中为TreinId创建的字典
调用SqlBulkCopy
,上传数据
创建一个key=Date+Time+FoutCode+TreinNaam,value=FoutId的内存字典,使用DataReader
从现有(新)数据填充它。看起来这有点复杂,也许有更好的方法来定义此查找
使用文本文件中的数据填充ExtraInfo
表,并使用步骤5中创建的字典将FK值返回到Fouten
调用SqlBulkCopy
,上传数据
现有结构的其他注意事项
运行并查看是否有其他因素导致您不知道的缓慢插入(例如插入中的未调优SELECT语句)。如果您看到定义的单个插入语句非常昂贵,则执行上述SqlBulkCopy
几乎没有影响
正如您在注释中所指出的,您的表很大。在INSERT语句中,您一次执行一个SELECT语句,同时也为每个语句执行一个SELECT。如果您的索引定义不正确,则可能会对每个INSERT中的每个SELECT语句执行表扫描。这将导致巨大的性能损失。最佳修复方法如下:
通过缓存字典中内存中可能的值列表,从插入中删除select。使用DataReader完成此操作
调整索引以确保它们在SELECT
语句的INSERT
部分中使用
确保在INSERT命令中定义的数据与架构中的数据类型完全匹配。例如:如果您有一个NVARCHAR列,但将该类型定义为VARCHAR,则可能需要更长的时间,或者数据库中有一个BIGINT