2012-04-01 213 views
2

有沒有辦法限制WMI用WQL語句檢索的條目數? 我這樣說是因爲運行一個查詢來檢索所有的Win32_NTLogEvent實例正在取得永久!我真正需要的是最近的事件(大約一週,或2000條目)WMI太慢了

這是我用來獲取日誌數據的代碼片段。其他查詢,如Win32_Processor,很好,很快。

  if (Configuration.OnlyErrorLogs) 
      { 
       // If Information logs should be suppressed, only get events where event type is not 3 
       WMIDataTemp1 = DataRetriever.GetWMIData("Win32_NTLogEvent", "EventType<>3"); 
      } 
      else 
      { 
       WMIDataTemp1 = DataRetriever.GetWMIData("Win32_NTLogEvent"); 
      } 
      foreach (ManagementObject Object in WMIDataTemp1) 
      { 
       this.Log.Add(new Log(Object)); 
      } 

而且功能獲得WMI數據如下:

public static ManagementObject[] GetWMIData(string wmiClass) { return GetWMIData(wmiClass, "", "CIMV2"); } 
    public static ManagementObject[] GetWMIData(string wmiClass, string whereClause) { return GetWMIData(wmiClass, whereClause, "CIMV2"); } 
    public static ManagementObject[] GetWMIData(string wmiClass, string whereClause, string nameSpace) 
    { 
     try 
     { 
      // If a where clause has been set, prepare the clause to add to the query string 
      if (whereClause != "") 
      { 
       whereClause = " WHERE " + whereClause; 
      } 
      // Create a search query 
      string query = "SELECT * FROM " + wmiClass + whereClause; 
      ManagementObjectSearcher wmiSearcher = new ManagementObjectSearcher("root\\" + nameSpace, query); 
      ManagementObjectCollection matches = wmiSearcher.Get(); 

      // Create an array to hold the matches 
      ManagementObject[] matchArray = new ManagementObject[matches.Count]; 

      // If matches found, copy to output 
      if(matches.Count > 0) 
      { 
       // Copy the search matches into this array 
       matches.CopyTo(matchArray, 0); 
      } 

      // Return array 
      return matchArray; 
     } 
     catch (Exception e) 
     { 
      ErrorDialogue errorReporter = new ErrorDialogue(e); 
      return null; 
     } 
    } 

如果每個日誌被存儲:

public class Log 
{ 
    public string Category = "N/A"; 
    public string DateTime = "N/A"; 
    public UInt16 ID = 0; 
    public string Level = "N/A"; 
    public string Message = "N/A"; 
    public string Source = "N/A"; 

    public Log() { } 
    public Log(ManagementObject wmiLogEvent) 
    { 
     this.GetInfo(wmiLogEvent); 
    } 

    public void GetInfo(ManagementObject wmiLogEvent) 
    { 
     try 
     { 
      this.Category = DataRetriever.GetValue(wmiLogEvent, "CategoryString"); 
      this.DateTime = DataRetriever.GetValue(wmiLogEvent, "TimeGenerated"); 
      this.ID = DataRetriever.GetValueUInt16(wmiLogEvent, "EventIdentifier"); 
      this.Level = DataRetriever.ConvertEventType(DataRetriever.GetValueUInt16(wmiLogEvent, "CategoryString")); 
      this.Message = DataRetriever.GetValue(wmiLogEvent, "Message"); 
      this.Source = DataRetriever.GetValue(wmiLogEvent, "SourceName"); 
     } 
     catch (Exception e) 
     { 
      ErrorDialogue errorReporter = new ErrorDialogue(e); 
     } 
    } 
} 
+0

對於使用上面的代碼的人,請注意,有些情況下,它使用matches.Count兩個地方。這會導致枚舉每次都重新開始並迭代,以獲取計數,然後重置回原始位置。 (您可以通過將Rewindable選項設置爲False來證明這一點。)將代碼「if(matches.Count> 0)」更改爲「if(matchArray.Length> 0)」的速度是其兩倍。 – 2017-01-17 14:37:48

回答

4

一種選擇是使用WHERE子句指定的範圍內你想要的條目...

例如,你可以使用TimeGeneratedWHERE子句中指定基於時間的範圍...

另一個選項是在創建ManagementObjectSearcher時相應地設置BlockSize

您可以使用它來指定您想要每次調用2000個條目 - 例如與ORDER BY TimeGenerated DESC一起,這應該會給出一個很好的結果。

+0

你可以擴展'BlockSize'嗎?這將如何工作;它完成了什麼? 我可以在WHERE條款中添加什麼? – CJxD 2012-04-01 17:32:32

+0

默認情況下,Windows 7中的日誌大小爲20meg,因此可能需要一些時間才能枚舉20mg的數據並通過WMI傳回。 – 2012-04-01 17:32:40

+0

@ErikPhilips授予;任何手動讀取文件並將其組織到我的數據容器中的方法?我將發佈容器類的外觀。 – CJxD 2012-04-01 17:35:43

1

速度對於WMI來說並不是一個強項。它往往是相當記憶密集的。但是,這個問題已經得到解決,您可以做幾件事情。從Microsoft TechNet檢出Why are my queries taking such a long time to complete?

+0

因此,據我所知,沒有什麼比LIMIT語句減少檢索項目的數量? – CJxD 2012-04-02 15:41:05

+0

正確。沒有辦法「限制」查詢。但是,如果您不需要多次迭代數據,則可以嘗試使用半同步方法,從而節省一些開銷。 – Nilpo 2012-04-02 16:22:03