【问题标题】:WMI is being too slowWMI 太慢了
【发布时间】:2012-04-01 17:22:17
【问题描述】:

有没有办法限制 WMI 使用 WQL 语句检索的条目数? 我这样说是因为运行查询来检索所有 Win32_NTLogEvent 实例需要永远!我真正需要的是最近的事件(大约一周,或 2000 个条目)

这是我用来获取日志数据的代码的 sn-p。其他查询,如 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);
        }
    }
}

【问题讨论】:

  • 对于任何使用上述代码的人,请注意有两个地方使用了matches.Count。这会导致枚举每次都倒回到开头并迭代,以获取计数,然后重置回其原始位置。 (您可以通过将 Rewindable 选项设置为 False 来证明这一点。)将代码“if(matches.Count > 0)”更改为“if(matchArray.Length > 0)”的速度是原来的两倍。

标签: c# wmi


【解决方案1】:

一种选择是使用WHERE 子句来指定所需条目的范围...

例如,您可以在WHERE 子句中使用TimeGenerated 来指定基于时间的范围...

另一个选项是在创建ManagementObjectSearcher 时相应地设置BlockSize

例如,您可以使用它来指定每次调用需要 2000 个条目 - 连同 ORDER BY TimeGenerated DESC 这应该会产生不错的结果。

【讨论】:

  • 你能扩展BlockSize吗?那将如何工作?它完成了什么?我可以在WHERE 子句中添加什么?
  • 默认情况下,Windows 7 中的日志大小为 20meg,因此枚举 20mg 的数据并通过 WMI 传回可能需要一些时间。
  • @ErikPhilips 授予;任何手动读取文件并将其组织到我的数据容器中的方式?我将发布容器类的样子。
  • @CJxD BlockSize 告诉搜索对象每次调用应该返回多少条目...更新了我的答案... HTH
  • @Yahia 看起来不错,但是从使用 CIM_Service 示例的快速测试来看,每个块获得 2000 个而不是每个块 2 个似乎并没有节省太多时间。我还需要弄清楚它在我的 ManagementObjectSearcher 解决方案而不是 ManagementClass 方法的上下文中如何工作 - 这并不完全清楚。
【解决方案2】:

速度并不是 WMI 的强项。它往往会占用大量内存。但是,问题已得到解决,您可以做一些事情。查看来自 Microsoft TechNet 的 Why are my queries taking such a long time to complete?

【讨论】:

  • 据我所知,没有什么比 LIMIT 语句更能减少它检索到的项目的数量了吗?
  • 正确。没有办法“限制”查询。但是,如果您不需要多次迭代数据,您可以尝试半同步方法,这样可以节省一点开销。
【解决方案3】:

现在使用 System.Diagnostics.EventLog 类作为更快的替代方案。与 WMI 相比,对程序更有利。

http://msdn.microsoft.com/en-us/library/system.diagnostics.eventlog.aspx

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2013-03-10
    • 2014-06-07
    • 2016-05-31
    • 2011-07-07
    • 2015-08-23
    • 2012-07-05
    • 2016-01-08
    • 2014-03-12
    相关资源
    最近更新 更多