C# 将多行从ConcurrentQueue插入SQL Server表
我有一个c应用程序,它从一个数据库中获取数据,进行必要的转换,并将数据插入另一个数据库的表中。为此,我将源数据插入队列,然后处理队列以将数据插入目标表。我有两个单独的线程来读取源数据和写入目标数据。读线程的运行速度比写线程快得多,所以我的队列很快就填满了 正如您在读取线程中看到的,我正在使用SqlCommand.ExecuteReader来读取数据。然后我在队列中循环,为每一行执行单独的INSERT语句。我设想的是,不是逐行插入,而是执行某种可能的Linq语句。有人知道如何更快地完成我的插入吗 队列定义:C# 将多行从ConcurrentQueue插入SQL Server表,c#,sql-server,concurrent-queue,C#,Sql Server,Concurrent Queue,我有一个c应用程序,它从一个数据库中获取数据,进行必要的转换,并将数据插入另一个数据库的表中。为此,我将源数据插入队列,然后处理队列以将数据插入目标表。我有两个单独的线程来读取源数据和写入目标数据。读线程的运行速度比写线程快得多,所以我的队列很快就填满了 正如您在读取线程中看到的,我正在使用SqlCommand.ExecuteReader来读取数据。然后我在队列中循环,为每一行执行单独的INSERT语句。我设想的是,不是逐行插入,而是执行某种可能的Linq语句。有人知道如何更快地完成我的插入吗
private static readonly BlockingCollection<HistorianData> ValueQueue = new BlockingCollection<HistorianData>(new ConcurrentQueue<HistorianData>(), 1000000);
阅读:
public static void EnqueueHistorianData(SqlConnection connection, int idToAdd, DateTime minDatetime, DateTime maxDateTime, string cluster, string dbName, string dataTable, string idTable, string mainIdColumn, string foreignIdColumn, string dateColumn, string nameColumn, string valueColumn)
{
StringBuilder select = new StringBuilder();
HistorianData values;
select.Append(String.Format("SELECT {0}.{1},", dataTable, dateColumn));
select.Append(String.Format(" '{0}.' + {1}.{2},", cluster, idTable, nameColumn));
select.Append(String.Format(" {0}.{1}", dataTable, valueColumn));
select.Append(String.Format(" FROM {0}.{1}", dbName, dataTable));
select.Append(String.Format(" JOIN {0}.{1}", dbName, idTable));
select.Append(String.Format(" ON {0}.{1} = {2}.{3}", dataTable, foreignIdColumn, idTable, mainIdColumn));
select.Append(String.Format(" INNER JOIN Runtime.dbo.Tag"));
select.Append(String.Format(" ON Runtime.dbo.Tag.TagName = '{0}.' + {1}.{2}", cluster, idTable, nameColumn));
select.Append(String.Format(" WHERE {0}.{1} >= '{2}'", dataTable, dateColumn, minDatetime.ToString()));
select.Append(String.Format(" AND {0}.{1} = {2}", dataTable, foreignIdColumn, idToAdd.ToString()));
select.Append(String.Format(" AND {0}.{1} >= '{2}'", dataTable, dateColumn, minDatetime.ToString()));
select.Append(String.Format(" AND {0}.{1} < '{2}'", dataTable, dateColumn, maxDateTime.ToString()));
using (var command = new SqlCommand(select.ToString(), connection))
{
command.CommandTimeout = 1000;
using (var reader = command.ExecuteReader())
{
if (reader.HasRows)
{
while (reader.Read())
{
values = new HistorianData();
values.SampleDate = reader.GetDateTime(0);
values.TagName = reader.GetString(1);
values.TagValue = reader.GetDouble(2);
ValueQueue.Add(values);
}
values = null;
reader.Close();
}
}
}
}
写作:
public static void WriteQueueValuesToHistorian(string connectionString)
{
HistorianData values;
using (var connection = new SqlConnection(connectionString))
{
connection.Open();
using (SqlCommand insertCommand = connection.CreateCommand())
{
insertCommand.CommandType = CommandType.Text;
insertCommand.CommandText = "INSERT INTO Runtime.dbo.History (DateTime, TagName, Value, QualityDetail) VALUES (@P1, @P2, @P3, 192)";
insertCommand.CommandTimeout = 1000;
var param1 = new SqlParameter("@P1", SqlDbType.DateTime);
insertCommand.Parameters.Add(param1);
var param2 = new SqlParameter("@P2", SqlDbType.NVarChar, 512);
insertCommand.Parameters.Add(param2);
var param3 = new SqlParameter("@P3", SqlDbType.Float);
insertCommand.Parameters.Add(param3);
insertCommand.Prepare();
while (!ValueQueue.IsCompleted && ValueQueue.TryTake(out values, System.Threading.Timeout.Infinite))
{
int retries = 0;
while (retries < 3)
{
insertCommand.Parameters["@P1"].Value = values.SampleDate.ToLocalTime();
insertCommand.Parameters["@P2"].Value = values.TagName;
insertCommand.Parameters["@P3"].Value = values.TagValue;
try
{
insertCommand.ExecuteNonQuery();
retries = 4;
}
catch (SqlException)
{
retries += 1;
sw.WriteLine("SQLException - Values: " + insertCommand.Parameters["@P1"].Value + ", " + insertCommand.Parameters["@P2"].Value + ", " + insertCommand.Parameters["@P3"].Value);
}
}
}
}
}
}
您可以从正在检索的数据创建DataTable,并使用SqlBulkCopy方法。请检查以下网址
该类确实通过从内置的SqlDataReader读取进行了优化。与其将记录读取到并发队列,然后再将其写回,是否可以只使用第一个函数中的SqlBulkCopy on reader?我尝试了这种方法。我的目标数据库实际上是专有的,通过使用自定义OLEDB接口的链接服务器引用。大容量插入不适用于链接服务器。两个函数的连接字符串是否指向同一个SQL server链接服务器是否与源数据库链接在同一个服务器上?如果是这样,为什么要通过C,为什么不在一个查询中直接查询呢。我的目标数据库实际上是专有的,通过使用自定义OLEDB接口的链接服务器引用。批量插入不适用于链接服务器。对DatabaseHelper类使用两个不同的连接字符串怎么样?如果这不起作用,那么您也可以尝试BulkInsert方法: