我想以非常高的速度将数据插入到sqlserver中。所以,我在c#.net中使用事务但是在使用事务之后我注意到插入的速度与没有使用它没有区别。请检查我的代码并帮我解决。
代码:
void ReadToTable()
{
try
{
if (dir != "")
{
dic.Clear();
string[] lines = System.IO.File.ReadAllLines(dir);
foreach (string line in lines)
{
SqlConnection sqlconn = new SqlConnection(DBsetting.Connstring);
sqlconn.Open();
SqlTransaction transaction = sqlconn.BeginTransaction();
if (!string.IsNullOrEmpty(line))
{
l = line.Split('\t');
l[0] = l[0].Trim();
l[1] = l[1].Trim();
l[2] = l[2].Trim();
l[3] = l[3].Trim();
if (!string.IsNullOrEmpty(l[0]) && l[3] == "1" || l[3] == "0")
{
dic.Add(new KeyValuePair<string, string>(l[0], l[1]));
PersianCalendar persCal = new PersianCalendar();
SqlCommand sqlda = new SqlCommand("insert into readd(IDp,date,day,nobatkari)values(@IDp,@date,@day,@nobatkari)", sqlconn, transaction);
sqlda.Transaction = transaction;
sqlda.Parameters.AddWithValue("@date", l[1]);
sqlda.Parameters.AddWithValue("@IDp", l[0]);
sqlda.Parameters.AddWithValue("@day", GetDayOfWeek(GetPerDate(l[1])));
sqlda.Parameters.AddWithValue("@nobatkari", "");//ntkari[idx].ToString());
sqlda.ExecuteNonQuery();
transaction.Commit();
sqlconn.Close();
sqlconn.Dispose();
}
else
{
ReadDataAndInsertIntoTable(line);
}
}
}
RefGrid();
foreach (var pair in dic)
{
InsertNobatKari(pair.Key, GetPerDate(pair.Value).ToString());
}
}
}
catch (Exception ex)
{
if (ex.Message.Contains("there is no row at position 0"))
{
MessageBox.Show("لطفا سطر خالی را انتخاب ننمایید");
}
else if (ex.Message.Contains("Cannot insert duplicate key row in object"))
{
MessageBox.Show("امکان ورود سطر تکراری وجود ندارد");
}
else
{
MessageBox.Show(ex.Message);
}
}
finally
{
}
}
答案 0 :(得分:3)
我想以非常高的速度将数据插入到sqlserver中。所以我在c#.net中使用事务但是在使用事务之后我注意到插入的速度与没有使用它没有区别。
是的,您不会看到改进,因为交易不是为了提高速度。另外,您没有正确使用交易:您没有提交交易。
您的方法
想想你在做什么。您正在循环文件中的行,并为您创建数据库连接的每一行,然后一直到数据库插入一条记录。您执行 n 次,其中 n 是文本文件中的记录数。
另一件事是你正在使用File.ReadAllLines
将整个文件读入内存:如果文件真的很大怎么办?你的记忆能处理吗?
更好的方法
更好的方法是创建一个连接,然后转到数据库并获取一批记录(50,100或更多)并在一次旅行中完成。继续这样做,直到所有记录都在。
此外,您应该使用File.ReadLines
,因此它将懒惰地读取每一行(一旦请求,它将把行加载到内存中)。
要提高速度,请使用SqlBulkCopy。确保阅读列映射上的部分。
步骤:
基于这一行创建内存中的表结构。
string[] strArray = line.Split('\t');
var dt = new DataTable();
for (int index = 0; index < strArray.Length; index++)
dt.Columns.Add(new DataColumn());
从文件中填充内存数据表:
do
{
DataRow row = dt.NewRow();
string[] itemArray = line.Split('\t');
row.ItemArray = itemArray;
dt.Rows.Add(row);
i = i + 1;
line = sr.ReadLine();
} while (!string.IsNullOrEmpty(line));
将数据发送到数据库:
var bc = new SqlBulkCopy(dbConn, SqlBulkCopyOptions.TableLock, null)
{
DestinationTableName = "TestData",
BatchSize = dt.Rows.Count
};
dbConn.Open();
bc.WriteToServer(dt);
dbConn.Close();
bc.Close();
如果文件非常大,您可以批量执行第4步。在上面的代码中,sr
变量将是StreamReader
的一个实例,但无论如何都可以使用它来读取文件。
注意:
此代码不能复制粘贴,而是用作指南,因此您需要根据自己的需要进行调整。
答案 1 :(得分:0)
您为每个插入的行创建一个事务,这与没有事务的所有操作几乎相同。你可能应该这样做:
string[] lines = System.IO.File.ReadAllLines(dir);
SqlConnection sqlconn = new SqlConnection(DBsetting.Connstring);
sqlconn.Open();
SqlTransaction transaction = sqlconn.BeginTransaction();
foreach (string line in lines)
{
...
}
transaction.Commit();
sqlconn.Close();
sqlconn.Dispose();