Sql Server Profiler作為Microsoft Sql Server資料庫系列的性能工具,通過它可以對資料庫的運行狀況進行即時跟蹤,從中可以找到慢查詢或者鎖死的SQL語句,從而去優化系統。本文介紹如果通過Silverlight來對Sql Server Profiler進行即時監控(資料庫環境以Sql Server 2005為例)

 

首先,先來看下SqlServer資料庫自帶的性能工具Sql Server Profiler,新建一個跟蹤:
0949525962-0  
我們選擇預設的範本Standard,其他都不變,點擊運行:

0949526145-1  

從中可以看到資料庫中的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的結束時間,當然一些隱藏的列我就不一一列舉了,有興趣大家可以勾選查看下。
如果我要定義一個符合自己需要的範本呢,那麼可以通過新建/編輯範本來實現:

09495221M-2  

上面有很多的事件種類的選擇,可以根據自己的需要定制Event,這裡我以最簡單的方式,就選擇了TSQL:SQL BatchCompleted:

0949525A7-3  

並且列選擇一個資料庫DatabaseName,類似于編輯 MyEnt,這樣該範本檔只會在MyEnt為名稱的資料庫中進行SQL執行跟蹤了:

094952C15-4  

最後點擊保存即可

 

那麼,在.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的即時監控。
兩個專案很簡單:
094952H37-5  
先運行 SqlServerProfier.Host程式:
09495250a-6  
正在對外發送監控資料,
然後運行宿主SL用戶端程式的Web端:
094952G03-7  
如果是慢查詢的部分,我會用紅色把它標紅,從而確定慢查詢語句,優化系統

總結:
當然,你還可以在監控程式中,對於追蹤記錄進行Log寫入或者一個特定Log表的插入,通過Web端(不管是Silverlight還是asp.net mvc均可以查詢相關的追蹤記錄),從而達到對於資料庫SQL執行的監控。
作者:Leepy

郵箱:sunleepy(AT)gmail.com

出處:HTTP://liping13599168.cnblogs.com/
創作者介紹
創作者 shadow 的頭像
shadow

資訊園

shadow 發表在 痞客邦 留言(0) 人氣()