【发布时间】:2012-02-28 22:40:57
【问题描述】:
我有一个从查询中填充的数据集,如下所示...
SELECT DISTINCT ColA, ColB, ColC, ColD, ColE, ColF, dbo.CustomFunction(ColA) AS ColG
FROM TableA
JOIN ViewA ON ColA = ViewColA
WHERE ColB = @P1 AND ColC = @P2 AND ColD = @P3 AND ColE = @P4
ORDER BY ColB, ColC DESC, ColA
(查询字段等被混淆)
我已经分析了这个查询,它在 SSMS 中运行 12 秒后返回了大约 200 行。请注意,我重新启动了服务器并使用了所需的 DBCC 命令来确保没有使用现有的执行计划。
但是,当我从 .Net 应用程序运行此查询时,填充数据集需要 30 多秒,并且默认 ADO.Net 命令超时 30 秒。
如果查询在 12 秒内运行,我无法理解为什么将 200 行填充到数据集中需要超过 18 秒。除非这里发生了我不知道的事情。我想 ADO.Net 只是调用查询,获取数据并填充它。
人口代码看起来像这样(注意我从另一个开发人员那里继承了这个)...
DataSet res = new DataSet();
try
{
using (SqlDataAdapter da = new SqlClient.SqlDataAdapter())
{
var cmd = new SqlClient.SqlCommand();
String params = FillParameters(cmd, _params, params);
cmd.CommandText = params + SQL;
cmd.Connection = conn;
cmd.Transaction = _transaction;
if (CommandTimeout.HasValue)
{
cmd.CommandTimeout = CommandTimeout.Value;
}
da.SelectCommand = cmd;
da.Fill(res);
return res;
}
}
catch
{
throw;
}
在调试中运行它,当填充方法被命中时,该方法大约需要 50 秒才能完成。这可以通过在 ADO.Net 命令上设置高超时来证明。我对查询的性能感到满意,我可以在大约 12 秒内始终如一地运行,那么为什么要额外花费 18 多秒来填充数据集?
ADO.Net 是否在执行此代码的某些操作(可能是由于结构原因),这意味着填充数据集需要超过 18 秒?我尝试将 EnforceConstraints 设置为 false,这没有任何区别。
需要注意的一点是,由于该程序的设计,将超过所需数量的参数输入到 sql 命令中。 FillParameters 方法执行此操作。有 20 个左右的“默认”参数添加到命令中,但只有例如此查询使用了 4 个。
总之,
会发生什么导致填充 DS 需要 18 秒以上的时间?
ADO.Net 是否对我的数据集做了一些“聪明”的事情,而不仅仅是运行查询和填充数据集?
可能是传入的参数过多导致了问题。
谢谢。
【问题讨论】:
-
这一行发生了什么 -> cmd.Transaction = _transaction; ADO.NET 命令支持事务,但事务在服务器上执行效率最高,即在 proc 中使用 BEGIN TRANSACTION。
-
@kd7 - 在这种情况下 _transaction 为空,它不应该影响任何东西。这是我在很多地方看到的通用程序。我认为当它用于更新时,可以将事务传递给它。
-
您是否使用相同的连接设置运行?特别是来自 .Net 的调用中的事务隔离级别是什么?事务隔离级别等连接设置会影响查询的时间。另外,我认为 12 秒是一个很长的时间,除非你有几千万或几亿行。请考虑更好的索引。
-
@Ben - 查询很好,因为有很多数据要处理。我不明白的是,运行查询只需要 12 秒,而 ADO.Net 又需要 28 多秒才能将该数据填充到数据集中?
-
从 `select transaction_isolation_level,* from sys.dm_exec_sessions' 中找出进程的事务隔离级别 Session_id 是会话的 SPID。 host_name 和 program_name 将帮助从列表中识别正确的会话。