EntityFramework之监听者判断SQL性能指标

简介:

DbCommandInterceptor

不用讲从字面意思我们就能立马明白大概是【监听命令】,我们看下该类,如下:

我们无需多加细看,看这几个虚方法我们马上就能明白和我们之前猜测的一致,就是进行数据库操作的SQL命令。在这个类中有一个重要的类那就是 DbCommandInterceptionContext ,我们姑且叫做监听SQL命令的上下文吧,我们再看这个类中包含什么。如下:

在这个类中有一个重要的属性 UserState ,哦,意思是用户状态,根据摘要信息得知,我们可以设置我们进行操作的相关信息,同时还是个object类型,看来是利于对象之间的转换而给。

接下来进入主题,我们如何去判断SQL性能指标呢?答案:我们检索出执行SQL时以及执行SQL完成后的消耗时间即可。

SQL性能判断指标

那么问题来了,我们该如何正确这个时间呢?此问题又可以细分为两个步骤。

(1)如何知道SQL命令是正在执行时以及执行完成呢?

(2)知道了之后我们又如何设置以及获取时间呢?

我们一一来划分,首先我建立一个类 SQLProfiler ,而此类肯定是继承于 DbCommandInterceptor ,所以代码就变成了这样。

复制代码

    public class SQLProfiler : DbCommandInterceptor
    {        public override void ReaderExecuting(DbCommand command, DbCommandInterceptionContext<DbDataReader> interceptionContext)
        {
            Executing(interceptionContext);            base.ReaderExecuting(command, interceptionContext);
        }        public override void ReaderExecuted(DbCommand command, DbCommandInterceptionContext<DbDataReader> interceptionContext)
        {
            Executed(command, interceptionContext);            base.ReaderExecuted(command, interceptionContext);
        }        public override void NonQueryExecuting(DbCommand command, DbCommandInterceptionContext<int> interceptionContext)
        {
            Executing(interceptionContext);            base.NonQueryExecuting(command, interceptionContext);
        }        public override void NonQueryExecuted(DbCommand command, DbCommandInterceptionContext<int> interceptionContext)
        {
            Executed(command, interceptionContext);            base.NonQueryExecuted(command, interceptionContext);
        }        public override void ScalarExecuting(DbCommand command, DbCommandInterceptionContext<object> interceptionContext)
        {
            Executing(interceptionContext);            base.ScalarExecuting(command, interceptionContext);
        }        public override void ScalarExecuted(DbCommand command, DbCommandInterceptionContext<object> interceptionContext)
        {
            Executed(command, interceptionContext);            base.ScalarExecuted(command, interceptionContext);
        }
}

复制代码

貌似发现了什么,好像方法参数都是什么DbCommand和DbCommandInterCeptionContext,既然这样,我们依样画葫芦诺,为了从执行SQL命令开始,我们此时从这里开始计时,将计时对象给UserState即可,于是就有了下面的代码。

复制代码

        private void Executing<T>(DbCommandInterceptionContext<T> interceptionContext)
        {            var timer = new Stopwatch();
            interceptionContext.UserState = timer;
            timer.Start();
        }

复制代码

此时应该就明朗了,我们在执行完成后来获取该计时对象并利用是否出现异常和我们指定设置的时间来判断其最终所花费的时间。执行完成后代码如下:

复制代码

        private void Executed<T>(DbCommand command, DbCommandInterceptionContext<T> interceptionContext)
        {            var timer = (Stopwatch)interceptionContext.UserState;
            timer.Stop();            if (interceptionContext.Exception != null)
            {
                File.AppendAllLines(
                    _logFile,                    new string[]
                {                "错误SQL语句",
                interceptionContext.Exception.Message,
                command.CommandText,
                Environment.StackTrace,                string.Empty,                string.Empty,
                });
            }            else if (timer.ElapsedMilliseconds >= _executionTime)
            {
                File.AppendAllLines(
                    _logFile,                    new string[]
                {                string.Format("耗时SQL语句({0}ms)",timer.ElapsedMilliseconds),
                command.CommandText,
                Environment.StackTrace,                string.Empty,                string.Empty,
                });
            }
        }

复制代码

上述 _executionTime 是我们在此类构造函数中所设置的时间,构造函数如下:

复制代码

        private readonly string _logFile;        private readonly int _executionTime;        public SQLProfiler(string logFile, int executionTime)
        {
            _logFile = logFile;
            _executionTime = executionTime;
        }

复制代码

而logFile则是我么所要输出的日志。此时别忘记最重要的一件事,那就是DbConfiguration配置类中进行注册(或者在配置文件中进行注册)。如下:

复制代码

    public class MyDbConfiguration : DbConfiguration
    {        public MyDbConfiguration()
        {            this.AddInterceptor(new SQLProfiler(@"D:\log.txt", 1));
        }
    }

复制代码

接下来我们来进行检验结果。

检验成果

复制代码

           using (var ctx = new EntityDbContext())
            {
                SqlParameter[] parameter = { };
                ctx.Database.SqlQuery<Student>("select * from a", parameter).ToList();
                Console.ReadKey();
            }

复制代码

上述表a实际上是不存在的,我们就是要看看是否能检测到该异常并获取其时间。来,瞧一瞧。

【效果一】

【效果二】

















本文转自xsster51CTO博客,原文链接:http://blog.51cto.com/12945177/1932203 ,如需转载请自行联系原作者







相关文章
|
5月前
|
SQL 存储 开发框架
【Entity Framework】你必须了解的之自定义SQL查询
【Entity Framework】你必须了解的之自定义SQL查询
85 0
|
2月前
|
关系型数据库 MySQL 网络安全
5-10Can't connect to MySQL server on 'sh-cynosl-grp-fcs50xoa.sql.tencentcdb.com' (110)")
5-10Can't connect to MySQL server on 'sh-cynosl-grp-fcs50xoa.sql.tencentcdb.com' (110)")
|
4月前
|
SQL 存储 监控
SQL Server的并行实施如何优化?
【7月更文挑战第23天】SQL Server的并行实施如何优化?
92 13
|
4月前
|
SQL
解锁 SQL Server 2022的时间序列数据功能
【7月更文挑战第14天】要解锁SQL Server 2022的时间序列数据功能,可使用`generate_series`函数生成整数序列,例如:`SELECT value FROM generate_series(1, 10)。此外,`date_bucket`函数能按指定间隔(如周)对日期时间值分组,这些工具结合窗口函数和其他时间日期函数,能高效处理和分析时间序列数据。更多信息请参考官方文档和技术资料。
|
4月前
|
SQL 存储 网络安全
关系数据库SQLserver 安装 SQL Server
【7月更文挑战第26天】
58 6
|
4月前
|
存储 SQL C++
对比 SQL Server中的VARCHAR(max) 与VARCHAR(n) 数据类型
【7月更文挑战7天】SQL Server 中的 VARCHAR(max) vs VARCHAR(n): - VARCHAR(n) 存储最多 n 个字符(1-8000),适合短文本。 - VARCHAR(max) 可存储约 21 亿个字符,适合大量文本。 - VARCHAR(n) 在处理小数据时性能更好,空间固定。 - VARCHAR(max) 对于大文本更合适,但可能影响性能。 - 选择取决于数据长度预期和业务需求。
281 1