【发布时间】:2011-08-18 16:55:23
【问题描述】:
我有一个巨大的批处理操作,每隔几个月就会运行一次,解析文本文件并将其导入 Sql Server 数据库。该过程需要几天时间才能完成,我正在寻找加快速度的方法。大约 1/3 的时间用于解析文本,2/3 的时间用于数据库 I/O。
我认为一个简单的解决方案是将这些拆分成单独的线程。因此,当一个线程写入数据库时,另一个线程可以解析文本。我更改了代码以构建需要执行的 SqlCommand 对象列表,然后在解析完成后将这些对象传递给新线程执行。
在一个小示例中,在单个线程中执行一批 SqlCommand 对象需要 37 秒,然后当我切换到在单独的线程中执行这些对象时,我感到惊讶的是,该过程大大减慢了,总共需要 63.34 秒。我做了一些探索,最终决定在 Visual Studio 中运行一些性能分析。我运行 Instrumentation 来测量多线程版本的时间,当它在 31.04 秒内运行时我感到很惊讶。我多次重新运行所有测试,结果或多或少相同。因此,似乎在运行性能分析时,对工作负载的拆分会提高性能,但在不运行性能分析时会减慢。
如果有人可以帮助指出可能导致此问题的原因以及我应该在哪里解决它,那就太棒了!
测试在四核 VMware 虚拟机中运行,该虚拟机在 6 核主机上运行。
编辑:进一步研究后,违规行似乎是与解析相关的行,与数据库无关,主要是 fileText.Trim()。为什么这些在附加调试器的情况下运行速度要慢得多我不知道。
编码启动新线程
while (sqlWriterThread != null && sqlWriterThread.ThreadState == ThreadState.Running)
Thread.Sleep(0);
if (sqlWriterThread == null || sqlWriterThread.ThreadState == ThreadState.Stopped)
{
sqlWriterThread = new Thread(new ParameterizedThreadStart(SqlWriterThread));
sqlWriterThread.Name = "SqlWriterThread";
sqlWriterThread.Priority = ThreadPriority.Highest;
}
sqlWriterThread.Start(commandBatch);
Thread.Sleep(0);
查询执行代码
public void SqlWriterThread(object commandBatch)
{
List<SqlCommand> batch = (commandBatch as List<SqlCommand>);
using (SqlConnection connection = new SqlConnection(HelperDatabase.ConnectionString))
{
connection.Open();
SqlTransaction transaction = connection.BeginTransaction();
try
{
foreach (SqlCommand cmd in batch)
{
cmd.Connection = connection;
cmd.Transaction = transaction;
cmd.ExecuteNonQuery();
cmd.Dispose();
}
transaction.Commit();
}
catch
{
transaction.Rollback();
}
}
}
【问题讨论】:
-
您使用的 .net 框架版本是什么?
-
当您计时 63.34 秒时,您是否在附加调试器的情况下运行?点击 ctrl+f5 以在没有调试器的情况下运行,而只需按 f5 将在附加调试器的情况下运行,这会降低性能
-
@BrandonAGr - 这似乎解决了这个问题。如果您将其发布为答案,那么我会将其标记为已回答。这并不能解释为什么在附加调试器的情况下运行多个线程应该以仅运行单个线程的一半速度运行。这才是真正的奥秘。
标签: c# sql-server multithreading performance