zoukankan      html  css  js  c++  java
  • Silverlight实现对Sql Server Profiler的SQL实时监控

          Sql Server Profiler作为Microsoft Sql Server数据库系列的性能工具,通过它可以对数据库的运行状况进行实时跟踪,从中可以找到慢查询或者死锁的SQL语句,从而去优化系统。本文介绍如果通过Silverlight来对Sql Server Profiler进行实时监控(数据库环境以Sql Server 2005为例)

          首先,先来看下SqlServer数据库自带的性能工具Sql Server Profiler,新建一个跟踪:image

    我们选择默认的模板Standard,其他都不变,点击运行:

    image

    从中可以看到数据库中的SQL的运行状态,EventClass作为事件类型,TextData作为运行的SQL脚本,ApplicationName作为一个应用程序的执行源的名称,比如说,从.Net应用程序执行的SQL脚本就是.Net SqlClient Data Provider,再比如说,我直接从数据库客户端工具执行一条SQL语句,可以看到ApplicationName为 ”Microsoft SQL Server Management Studio - 查询“,因此我们通过ApplicationName字段得到程序的执行源,LoginName作为一个数据库的账户,一般系统用户为sa,包括CPU/Reads/Writes在此上面也是一目了然,Duration比较有用,可以查看执行语句的耗时,后面还包括StartTime的开始时间和EndTime的结束时间,当然一些隐藏的列我就不一一列举了,有兴趣大家可以勾选查看下。

          如果我要定义一个符合自己需要的模板呢,那么可以通过新建/编辑模板来实现:

    image

    上面有很多的事件类型的选择,可以根据自己的需要定制Event,这里我以最简单的方式,就选择了TSQL:SQL BatchCompleted:

    image

    并且列选择一个数据库DatabaseName,类似于编辑 MyEnt,这样该模板文件只会在MyEnt为名称的数据库中进行SQL执行跟踪了:

    image

    最后点击保存即可

          那么,在.Net上怎么实现对于Sql Server Profiler的使用和监控,实际上,Sql ServerProfiler本身为.Net开发的,后来我在SqlServer2005数据库的安装目录 C:\Program Files\Microsoft SQL Server\90\SDK\Assemblies 中,找到一个Microsoft.SqlServer.ConnectionInfo.dll,这个dll就可以实现执行Sql的监控。

          开始创建项目,其中,监控程序是一个控制台程序,而Silverlight客户端程序是一个对于SqlServerProfiler实时监控的展示,Silverlight的客户端程序通过Socket和监控程序进行通信。由于Silverlight对于TCP通信的限制,必须往监控程序发送策略请求,并且对于TCP通信来说,目前Silverlight的使用端口必须为4502-4530,于是必须在监控端先设置一个Policy.xml的策略文件:

    <?xml version="1.0" encoding ="utf-8"?> 
    <access-policy> 
      <cross-domain-access> 
        <policy> 
          <allow-from> 
            <domain uri="*" /> 
          </allow-from> 
          <grant-to> 
            <socket-resource port="4502-4530" protocol="tcp" /> 
          </grant-to> 
        </policy> 
      </cross-domain-access> 
    </access-policy>

    现在我将策略请求,监听SL客户端连接/数据收发请求,数据库监听跟踪请求,分别创建3个线程:

    //创建Socket来监听策略请求和发送

    this._policyThread = this.CreateThread(this.PolicyRequest); 
    //创建Socket来监听信息请求和发送 
    this._infoThread = this.CreateThread(this.InfoRequest); 
    //创建Socket来监听数据库跟踪请求和发送 
    this._traceServerThread = this.CreateThread(this.TraceServerRequest); 

    PolicyRequest,InfoRequest的方法具体看文章末尾的附件源代码,这里主要说一下TraceServerRequest的方法:

    SqlConnectionInfo conninfo = new SqlConnectionInfo(); 
    conninfo.ServerName = "机器名"
    conninfo.UserName = "数据库账户"
    conninfo.Password = "数据库密码"
    conninfo.UseIntegratedSecurity = false;
    TraceServer trace = new TraceServer(); 
    trace.InitializeAsReader(conninfo, TDF_FILE); 
    SqlConnectionInfo, TraceServer类来自于对Microsoft.SqlServer.ConnectionInfo的引用,其中TDF_FILE就是我前面说的跟踪模板文件名,它的文件后缀为tdf。
    while (trace.Read()) 

        var eventData = new EventData() 
        { 
            EventClass = trace["EventClass"].ToString(), 
            TextData = trace["TextData"] != null ? trace["TextData"].ToString() : ""
            ApplicationName = trace["ApplicationName"] != null ? trace["ApplicationName"].ToString() : ""
            NTUserName = trace["NTUserName"] != null ? trace["NTUserName"].ToString() : ""
            LoginName = trace["LoginName"] != null ? trace["LoginName"].ToString() : ""
            CPU = trace["CPU"] != null ? trace["CPU"].ToString() : ""
            Reads = trace["Reads"] != null ? trace["Reads"].ToString() : ""
            Writes = trace["Writes"] != null ? trace["Writes"].ToString() : ""
            Duration = trace["Duration"] != null ? trace["Duration"].ToString() : ""
            ClientProcessID = trace["ClientProcessID"] != null ? trace["ClientProcessID"].ToString() : ""
            SPID = trace["SPID"] != null ? trace["SPID"].ToString() : ""
            StartTime = trace["StartTime"] != null ? trace["StartTime"].ToString() : ""
            EndTime = trace["EndTime"] != null ? trace["EndTime"].ToString() : ""
        }; 
        var sendData = JsonConvert.SerializeObject(eventData); 
        if (string.IsNullOrEmpty(sendData)) 
            continue
        lock (_lock) 
        { 
            this._queues.Enqueue(sendData); 
        } 

    通过trace.Read()方法来得到trace的跟踪记录,这里我不会马上通过Socket发送到SL客户端,而是通过一个队列对跟踪记录进行人队,通过InfoRequest从队列中取出数据,发送给SL客户端:

    while (true

         lock (_lock) 
         { 
             if (this._queues.Count == 0
             { 
                 Thread.Sleep(200); 
                 continue
             } 
             var sendData = this._queues.Dequeue(); 
             Console.WriteLine(sendData);
             byte[] data = Encoding.GetEncoding("gb2312").GetBytes(sendData);
             // 移除已断开的套接字 
             this._clientList.RemoveAll(o => o.Connected == false); 
             foreach (Socket s in this._clientList) 
             {            
                 if (s.Connected) 
                 { 
                     try 
                     { 
                         //发送数据 
                         s.Send(data); 
                     } 

     

    SL客户端通过Socket异步编程接收数据

    /// <summary> 
    /// 当接收完成 
    /// </summary> 
    /// <param name="e"></param> 
    void ProcessReceive(SocketAsyncEventArgs e) 

         if (e.SocketError == SocketError.Success) 
         { 
             try 
             { 
                 Gb2312Encoding encoding = new Gb2312Encoding(); 
        
                 string data = Regex.Replace(encoding.GetString(e.Buffer, 0, e.Buffer.Length), @"\0"""); 
        
                 EventData eventData = JsonConvert.DeserializeObject<EventData>(data);
                 byte[] bytes = new byte[1024]; 
                 e.SetBuffer(bytes, 0, bytes.Length);
                 this._syn.Send(this.GetText, eventData);
                 //执行连接 
                 this._socket.ReceiveAsync(this._socketArgs);    
             } 

    //同步上下文调用的方法 
    private void GetText(object data) 

        if (data == null
            return
        EventData eventData = (EventData)data; 
        _list.Add(eventData); 
        this.Dispatcher.BeginInvoke(new Action(() => 
        { 
            this.dataGridRecords.ItemsSource = null
            this.dataGridRecords.ItemsSource = _list;
            this.dataGridRecords.UpdateLayout(); 
            this.dataGridRecords.SelectedIndex = _list.Count - 1
            this.dataGridRecords.ScrollIntoView(this.dataGridRecords.SelectedItem, null); 
        })); 

    这样就实现了Silverlight客户端对于Sql Server Profiler的实时监控。

    两个项目很简单:

    image

    先运行 SqlServerProfier.Host程序:

    image

    正在对外发送监控数据,

    然后运行宿主SL客户端程序的Web端:

    image

    如果是慢查询的部分,我会用红色把它标红,从而确定慢查询语句,优化系统

    总结:

          当然,你还可以在监控程序中,对于跟踪记录进行Log写入或者一个特定Log表的插入,通过Web端(不管是Silverlight还是asp.net mvc均可以查询相关的跟踪记录),从而达到对于数据库SQL执行的监控。

    附上源代码:SqlServerProfiler.rar

  • 相关阅读:
    2017-2018-1 20155326 实验四 外设驱动程序设计
    2017-2018-1 20155326 20155320《信息安全技术》实验四 木马及远程控制技术
    20155326 2017-2018-1 《信息安全系统设计基础》第六章课上考试题
    6月20日云栖精选夜读:阿里怎么发工资?自研薪酬管理系统首次曝光
    一个成功的研发团队应具备的9大属性
    那些创业的艰辛整理
    明明可以靠脸吃饭偏要靠才华_你身边有女神程序员吗?
    程序猿们_一二三四线城市你更愿意选择去哪里工作?
    微服务架构实践之邮件通知系统改造
    谈谈“僵尸猎手小明”手游兼容性踩到的坑
  • 原文地址:https://www.cnblogs.com/liping13599168/p/2525810.html
Copyright © 2011-2022 走看看