【问题标题】:Optimizing WMI query with Linq使用 Linq 优化 WMI 查询
【发布时间】:2012-12-19 07:15:43
【问题描述】:

首先,我应该承认我对使用 WMI 或 LINQ 真的不太了解。所以我敢肯定,任何人都不会感到惊讶,因为我遇到了这样的困难!

问题是我试图从同一个 WMI 对象中查询或返回多个值。通常这不会太糟糕,但我发现很难解决这个问题,因为只需要返回与特定数据集匹配的元素。问题是,我必须首先查询 WMI 以获取特定元素或值,然后重新启动查询,按所述元素或值过滤以返回所需的数据集。

我确信我可以遍历 WMI 对象中的所有元素并将它们附加到一个集合中。然后遍历集合,直到我得到我正在寻找的东西,但我仍然有过滤掉所有额外不必要元素的问题。

所以我想我的问题是,对 WMI 对象进行高级搜索的最佳方法是什么?如何优化该过程以便不需要很长时间来检索我正在寻找的信息?

在我的多次搜索中,我发现了一些关于使用 LINQ 的人的参考资料,但我对 LINQ 的了解有限,这意味着我不确定如何在这种情况下使用它,因此非常感谢任何帮助或见解。

这是我到目前为止的想法:

        ManagementObjectSearcher searcher = new ManagementObjectSearcher
            ("SELECT * FROM Win32_NetworkAdapterConfiguration where IPEnabled=true");
        IEnumerable<ManagementObject> objects = searcher.Get().Cast<ManagementObject>();
        string description = (from o in objects orderby o["IPConnectionMetric"] 
                              select o["Description"].ToString()).FirstOrDefault();

        _NICINDEX = (from o in objects orderby o["IPConnectionMetric"]
                     select o["Index"].ToString()).FirstOrDefault();

        _MACADDRESS = (from o in objects orderby o["IPConnectionMetric"]
                       select o["MACAddress"].ToString()).FirstOrDefault();

        _IPADDRESS = (from o in objects orderby o["IPConnectionMetric"]
                      select o["IPAddress"].ToString()).FirstOrDefault();

        _IPV6ADDRESS = (from o in objects orderby o["IPConnectionMetric"]
                        select o["IPAddress"].ToString()).FirstOrDefault();

        _SUBNETMASK = (from o in objects orderby o["IPConnectionMetric"]
                       select o["IPSubnet"].ToString()).FirstOrDefault();

        _GATEWAY = (from o in objects orderby o["IPConnectionMetric"]
                    select o["DefaultIPGateway"].ToString()).FirstOrDefault();

        _DNSSERVER = (from o in objects orderby o["IPConnectionMetric"]
                      select o["DNSServerSearchOrder"].ToString()).FirstOrDefault();

        _DNSSECSVR = (from o in objects orderby o["IPConnectionMetric"]
                      select o["DNSServerSearchOrder"].ToString()).FirstOrDefault();

        return description;

【问题讨论】:

  • 根据您正在寻找的信息..您认为“花了这么长时间”您实际上想要实现什么..如果您只想返回描述,那么为什么你的代码中还有其他的东西吗..?
  • 您确实意识到您在这里执行了 10 个单独的数据库查询,因为这是您迭代 IQueryable 对象的次数。您还可以提取数据的整个结果集,对其进行 10 次不同的排序,然后在 10 次不同的时间中获取相同的第一个值。我并不惊讶它很慢。
  • 说实话,返回并不重要,它只是我设置函数的方式,这不是我尝试的唯一查询。这里重要的是,因为我在 WMI 上执行了很多查询,这导致我的应用程序明显变慢。真的,我只是在寻找一种更好的方法来做同样的事情。
  • 还有他目前不应该编译的代码,因为所有 _Named 变量都没有正确声明.. 仍在等待 OP 说出他真正想要做什么.. 如果这些值例如 _DNSSECSVR 是声明为局部变量,请拍摄方法定义或您正在使用的未优化方法
  • 一种更好的方法是创建一个自定义类并传递您需要的值最好是分开并以较小的块/块来做事情而不是尝试以一种大而缓慢的方式来做所有事情跨度>

标签: c# linq optimization query-optimization wmi


【解决方案1】:

所以我不熟悉您的特定数据库提供商,但您的主要问题是您将 IEnumerable 迭代 10 次,这意味着对数据库的 10 个不同查询。你当然不需要这样做,这真的会影响你的表现。您还对返回的数据进行了 10 次不同的排序;你应该只做一次。

这是您的代码的重构,以获取项目一次,然后从中获取 10 个不同的值:

ManagementObjectSearcher searcher = new ManagementObjectSearcher
            ("SELECT * FROM Win32_NetworkAdapterConfiguration where IPEnabled=true");
ManagementObject managementObject = searcher.Get()
    .Cast<ManagementObject>()
    .OrderBy(obj => obj["IPConnectionMetric"])
    .FirstOrDefault();

string description = managementObject["Description"];
_NICINDEX  = managementObject["Index"];
//repeat for the other 8 values following the above pattern
return description;

请注意,如果可能的话,您应该在 DB 端进行排序,并在 DB 端将输出限制为 1 个值。在不知道您正在使用的查询提供程序的细节的情况下,我无法说出最好的方法是什么。

【讨论】:

  • 这个解决方案对我来说最有意义......但是,我刚刚意识到我还需要存储该对象中列出的所有网络适配器的 GUID。如何修改它以包含所有 GUID 条目的集合 - 而无需进行单独的查询?
【解决方案2】:

创建一个 WMI 查询来获取您需要的数据,将其转换为 LINQ to Objects 查询,然后遍历结果,获取您想要的数据位会更容易。

var queryStr =
    "SELECT * " +
    "FROM Win32_NetworkAdapterConfiguration " +
    "WHERE IPEnabled = true";
using (var searcher = new ManagementObjectSearcher(queryStr))
using (var managementQuery = searcher.Get())
{
    // convert to LINQ to Objects query
    var query =
        from ManagementObject mo in managementQuery
        orderby Convert.ToUInt32(mo["IPConnectionMetric"])
        select new
        {
            Description          = Convert.ToString(mo["Description"]),
            Index                = Convert.ToString(mo["Index"]),
            MACAddress           = Convert.ToString(mo["MACAddress"]),
            IPAddress            = String.Join(", ", (string[])mo["IPAddress"] ?? new string[0]),
            IPSubnet             = String.Join(", ", (string[])mo["IPSubnet"] ?? new string[0]),
            DefaultIPGateway     = String.Join(", ", (string[])mo["DefaultIPGateway"] ?? new string[0]),
            DNSServerSearchOrder = String.Join(", ", (string[])mo["DNSServerSearchOrder"] ?? new string[0]),
        };

    // grab the fields
    String description = null;
    foreach (var item in query)
    {
        description  = description  ?? item.Description;
        _NICINDEX    = _NICINDEX    ?? item.Index;
        _MACADDRESS  = _MACADDRESS  ?? item.MACAddress;
        _IPADDRESS   = _IPADDRESS   ?? item.IPAddress;
        _IPV6ADDRESS = _IPV6ADDRESS ?? item.IPAddress;
        _SUBNETMASK  = _SUBNETMASK  ?? item.IPSubnet;
        _GATEWAY     = _GATEWAY     ?? item.DefaultIPGateway;
        _DNSSERVER   = _DNSSERVER   ?? item.DNSServerSearchOrder;
        _DNSSECSVR   = _DNSSECSVR   ?? item.DNSServerSearchOrder;
        // check if all fields are set so we can stop
        if (new[] { description, _NICINDEX, _MACADDRESS, _IPADDRESS, _IPV6ADDRESS, _SUBNETMASK, _GATEWAY, _DNSSERVER, _DNSSECSVR }.All(x => x != null))
            break;
    }
}

虽然我不清楚为什么要单独获取每个字段的第一个。我希望您会希望将第一个适配器的字段作为一个整体。所以最后,我认为最终应该是:

var first = query.FirstOrDefault();
if (first != null)
{
    description  = first.Description;
    _NICINDEX    = first.Index;
    _MACADDRESS  = first.MACAddress;
    _IPADDRESS   = first.IPAddress;
    _IPV6ADDRESS = first.IPAddress;
    _SUBNETMASK  = first.IPSubnet;
    _GATEWAY     = first.DefaultIPGateway;
    _DNSSERVER   = first.DNSServerSearchOrder;
    _DNSSECSVR   = first.DNSServerSearchOrder;
}

【讨论】:

    猜你喜欢
    • 2021-07-13
    • 1970-01-01
    • 2019-04-15
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多