2012-04-01 3 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; 
     } 
    } 

Где каждый Log получает сохраненное:

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)» to «if (matchArray.Length> 0)». –

ответ

4

Одним из вариантов является использование пункта WHERE указать диапазон записей, которые вы хотите ...

Например, вы можете использовать TimeGenerated в предложении WHERE, чтобы указать временной диапазон ...

Другой вариант - установить BlockSize соответственно при создании ManagementObjectSearcher.

Вы можете использовать это, чтобы указать, что вы хотите 2000 записей за вызов, например, вместе с ORDER BY TimeGenerated DESC это должно дать хороший результат.

+0

Можете ли вы расширить 'BlockSize'? Как это будет работать; что он делает? И что я могу добавить в предложение 'WHERE'? – CJxD

+0

По умолчанию размеры журналов в Windows 7 равны 20 мг, поэтому может потребоваться некоторое время, чтобы перечислить данные на сумму 20 мг и передать их обратно через WMI. –

+0

@ ErikPhilips Предоставлено; каким образом можно вручную считывать файлы и организовывать их в свои контейнеры данных? Я опубликую, как выглядит класс контейнера. – CJxD

1

Скорость не является сильным костюмом для WMI. Это, как правило, довольно интенсивно. Однако вопрос был рассмотрен, и есть несколько вещей, которые вы можете сделать. Отъезд Why are my queries taking such a long time to complete? от Microsoft TechNet.

+0

Насколько я вижу, нет ничего похожего на инструкцию LIMIT, чтобы уменьшить количество элементов, которые она извлекает? – CJxD

+0

Исправить. Невозможно «ограничить» запрос. Однако, если вам не нужно перебирать данные более одного раза, вы можете попробовать полусинхронный подход, который экономит немного накладных расходов. – Nilpo

Смежные вопросы