我在WPF的项目中工作,它使用Entity Framework和SQL Server。最优化有废话。一切都太慢了。我想要诊断代码的哪些部分会影响性能 - 我认为只有少数(我的意思是很多但不是全部)设计不良并且会导致性能下降。
现在我们每个表都有类,例如UserRepository
。它不完全是存储库模式。这些类的方法如:GetAll(...), GetById(...), GetNewest(...), GetAllWithHigherSalaryThan(int salary, int companyId)
,等等,db的许多方法访问器。数据库仅用于存储库类。
我不想在这里谈论重构。我只想测量每个方法执行的时间以及在运行时执行的次数。通过这些信息,我将能够找到错误。
我想测量大约100个在许多类中“从db中选择”的方法。 SQL Server Profiler没有做到这一点,因为这些方法无数次执行,如果可能的话,使用我们的数据库方法分析来自profiler的日志是噩梦。
示例方法:
public IEnumerable<Foo> GetFoo(int y, int z)
{
return Context.Where(p =>
p.X == null &&
p.Y == y &&
p.Time >= z).OrderBy(x => x.Time).AsEnumerable();
}
现在我正在考虑为每个方法添加秒表,测量执行时间,计算执行次数并将其传递给某些单例或其他东西,然后显示它。当然,当我完成它时我会关闭这个诊断,但这种方法是非常周的课程,我需要编辑每个方法,我不知道如何关闭它 - 我的意思是我知道我可以使用像#define DEBUG
这样的东西,但无论如何都是蹩脚的。
我试图通过Reflections来解决问题,但没有任何影响...也许有办法在C#中查看方法的执行时间?
你推荐什么?
答案 0 :(得分:4)
我的第一个建议是一个合适的探查器,我的收藏是来自Jetbrains的dotTrace,但还有其他人。
如果某种方式不是一种选择,你坚持自己做:
我推荐Postsharp - 或其他AOP包。它可以做的是轻松地为许多方法添加方面。
使用Postsharp,您可以写一个方面:
[Serializable]
public class TraceAttribute : OnMethodBoundaryAspect
{
public override void OnEntry( MethodExecutionArgs args )
{
// start measuring time here
}
public override void OnExit( MethodExecutionArgs args )
{
// stop measuring here
}
}
然后将该方面应用于一堆方法(来自MyNamespace的所有公共方法):
#if DEBUG
[assembly: Trace( AttributeTargetTypes = "MyNamespace.*",
AttributeTargetTypeAttributes = MulticastAttributes.Public,
AttributeTargetMemberAttributes = MulticastAttributes.Public )]
#endif
这是一次性处理多种方法所需的所有代码。
我最近这样做了,我将所有测量结果放入csv文本文件中,然后将其转储到SQL Server中,我可以轻松地进行选择和分组,例如找出方法消耗的总时间。我没有使用分析器,因为我在生产环境中进行了测量 - 从仪器中获得的性能影响并不大(如果程序速度很慢)。
以下是有关的更多信息: http://www.postsharp.net/aspects/examples/logging
甚至免费版本的PostSharp Express就足以做到这一点。
答案 1 :(得分:0)
语言本身没有内置的探查器。如果你不介意指定你正在使用的内容,你的IDE / Debugger 可能有一些内置的分析器。
如果您按照指示运行MSSQL,则可能无法以适用于ya的方式进行概要分析。这是两个对我有神奇影响的查询:
SELECT TOP 10 SUBSTRING(qt.TEXT, (qs.statement_start_offset/2)+1,
((CASE qs.statement_end_offset
WHEN -1 THEN DATALENGTH(qt.TEXT)
ELSE qs.statement_end_offset
END - qs.statement_start_offset)/2)+1),
qs.execution_count,
qs.total_logical_reads, qs.last_logical_reads,
qs.total_logical_writes, qs.last_logical_writes,
qs.total_worker_time,
qs.last_worker_time,
qs.total_elapsed_time/1000000 total_elapsed_time_in_S,
qs.last_elapsed_time/1000000 last_elapsed_time_in_S,
qs.last_execution_time,
qp.query_plan
FROM sys.dm_exec_query_stats qs
CROSS APPLY sys.dm_exec_sql_text(qs.sql_handle) qt
CROSS APPLY sys.dm_exec_query_plan(qs.plan_handle) qp
ORDER BY qs.total_logical_reads DESC -- logical reads
-- ORDER BY qs.total_logical_writes DESC -- logical writes
-- ORDER BY qs.total_worker_time DESC -- CPU time
SELECT DISTINCT TOP 10
t.TEXT QueryName,
s.execution_count AS ExecutionCount,
s.max_elapsed_time AS MaxElapsedTime,
ISNULL(s.total_elapsed_time / s.execution_count, 0) AS AvgElapsedTime,
s.creation_time AS LogCreatedOn,
ISNULL(s.execution_count / DATEDIFF(s, s.creation_time, GETDATE()), 0) AS FrequencyPerSec
FROM sys.dm_exec_query_stats s
CROSS APPLY sys.dm_exec_sql_text( s.sql_handle ) t
ORDER BY
s.max_elapsed_time DESC
GO
这里的神奇之处在于你可以找出哪些命令总体上占用的时间最多,不管它是一个非常缓慢运行10次的命令,还是运行1,000,000次但非常快的命令。
你也可以通过更高级的东西逃脱。我之前通过将探查器附加到每个Web请求的开头和结尾来调试项目,但是再次找不到导致问题的特定命令。