C# 测量多种方法的执行时间

C# 测量多种方法的执行时间,c#,sql-server,entity-framework,C#,Sql Server,Entity Framework,我在WPF的项目中工作,该项目使用实体框架和SQL Server。那里的优化是废话。一切都太慢了。我想诊断代码的哪些部分会影响性能——我认为只有少数(我指的是很多,但不是全部)地方设计糟糕,会影响性能 现在,对于我们有类的每个表,例如UserRepository。这并不完全是存储库模式。这些类有如下方法:GetAll(…)、GetById(…)、getnewst(…)、GetAllWithHigherSalaryThan(int-salary、int-companyId),等等,许多方法访问数据

我在WPF的项目中工作,该项目使用实体框架和SQL Server。那里的优化是废话。一切都太慢了。我想诊断代码的哪些部分会影响性能——我认为只有少数(我指的是很多,但不是全部)地方设计糟糕,会影响性能

现在,对于我们有类的每个表,例如
UserRepository
。这并不完全是存储库模式。这些类有如下方法:
GetAll(…)、GetById(…)、getnewst(…)、GetAllWithHigherSalaryThan(int-salary、int-companyId)
,等等,许多方法访问数据库。数据库仅在存储库类中使用

我不想在这里谈论重构。我只想测量每个方法执行多长时间,以及在运行时执行了多少次。通过这些信息,我将能够找到bug

我想测量大约100个方法,这些方法在很多类中都有“从db中选择”。 SQLServerProfiler并没有做到这一点,因为这些方法执行了无数次,如果可能的话,使用我们的数据库方法分析来自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();
}
public IEnumerable GetFoo(inty,intz)
{
返回上下文。其中(p=>
p、 X==null&&
p、 Y==Y&&
p、 Time>=z).OrderBy(x=>x.Time).AsEnumerable();
}
现在我正在考虑在每个方法中添加秒表,测量执行时间,计算执行次数,并将其传递给某个单例或其他对象,然后显示它。当然,当我完成诊断后,我会关闭它,但这种方法非常简单,我需要编辑每个方法,我不知道如何在之后关闭它-我的意思是我知道我可以使用类似
#define DEBUG
的东西,但无论如何它都是蹩脚的

我试图通过思考找出一些问题,但没有效果。。。也许有一种方法可以在C#中查看方法的执行时间


你推荐什么

语言本身没有内置的分析器。如果您不介意指定所使用的内容,您的IDE/调试器可能有一些内置的探查器

如果您正在运行MSSQL(如图所示),您可能无法以适合您的方式进行评测。这里有两个问题对我起了神奇的作用:

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

这里的神奇之处在于,您可以找出哪些命令总体上占用的时间最多,而不管它是一个运行速度非常慢的命令10次,还是一个运行1000000次但非常快的命令


你也可能会得到一些更高的东西。我以前可以通过在每个web请求的开头和结尾附加一个探查器来调试项目,但这同样无法找到导致问题的特定命令。

我的第一个建议是一个合适的探查器,我最喜欢的是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中的所有公共方法):

这就是同时为许多方法提供工具所需的全部代码

我最近做了这件事,我把所有的测量数据转储到csv文本文件中,然后将其转储到SQL Server中,在那里我可以很容易地进行选择和分组,例如找出一个方法所消耗的总时间。我没有使用分析器,因为我是在生产环境中进行测量的——仪器对性能的影响不大(如果程序运行缓慢的话)

以下是关于这方面的更多信息:


即使是免费版本的PostSharp Express也足以做到这一点。

您是否尝试过使用VS profiler,它在VS2012及更高版本中非常好?我必须说,您看过非常漂亮的软件吗!我喜欢这种干净的方法。我还使用了一种包装器方法来做同样的事情,但它是日志框架的一部分,然后将执行时间和其他数据记录到数据库中。在这里,我认为你的方法非常适合。
[Serializable] 
public class TraceAttribute : OnMethodBoundaryAspect 
{ 
    public override void OnEntry( MethodExecutionArgs args ) 
    { 
        // start measuring time here
    } 

    public override void OnExit( MethodExecutionArgs args ) 
    { 
        // stop measuring here 
    } 
}
#if DEBUG 
[assembly: Trace( AttributeTargetTypes = "MyNamespace.*", 
    AttributeTargetTypeAttributes = MulticastAttributes.Public, 
    AttributeTargetMemberAttributes = MulticastAttributes.Public )] 
#endif