使用内部 .Any() 是否与执行两个单独的检查相同

本文关键字:单独 两个 检查 执行 内部 Any 是否 | 更新日期: 2023-09-27 18:19:09

我正在开发一个 asp.net mvc-5 Web应用程序。 我有以下 2 个模型类:-

public class ScanInfo
    {
        public TSServer TSServer { set; get; }
        public Resource Resource { set; get; }
        public List<ScanInfoVM> VMList { set; get; }
    }
public class ScanInfoVM
    {
        public TSVirtualMachine TSVM { set; get; }
        public Resource Resource { set; get; }
    }

现在这两个操作会是一样的吗:-

操作1

var vmlist = scaninfo.SelectMany(a => a.VMList).ToList();
if (vmlist.Any(a2 => a2.Resource.RESOURCENAME.ToLower() == vmname.ToLower()))

操作2

 if (scaninfo.Any(a=>a.VMList.Any(a2 => a2.Resource.RESOURCENAME.ToLower() == vmname.ToLower())))

或者它们将以不同的方式执行?

谢谢

使用内部 .Any() 是否与执行两个单独的检查相同

第一个选项有一个昂贵的操作,即使用 SelectMany 扁平化列表元素。

除此之外,两者应该工作相同,即在找到第一个匹配项时中断。

在数据库的情况下

如果此查询在数据库上执行,第一个选项是不好的,因为它会将所有数据带到应用程序内存(因为您使用的是ToList(,稍后它将在内存对象中执行Any检查。

第二个将在数据库端执行查询,并且仅将结果返回给应用程序。它不会将数据带回应用程序。

不,它们的执行方式会有所不同。

第一个要糟糕得多。 它会导致枚举 scaninfo,然后将所有 ScanInfoVM 放入一个列表中,然后使用 Any 过滤 ScanInfoVM。

第二个要好得多,但它正在检查是否存在任何具有符合您条件的 ScanInfoVM 的ScanInfo

简而言之,它们的执行方式不同,检查

的内容也略有不同,但是由于您只关心是否存在任何内容,因此它们应该给出相同的结果,但是第二个执行速度要快得多,仅从数据库中返回一个布尔值,它将停止查看它找到第一个,而您的第一个从数据库返回所有内容,然后开始检查。

如果您只是在第一个操作中删除ToList(),则需要运行探查器来确定哪个性能更好。 我怀疑它们会以相同的方式执行,但这取决于数据库提供程序如何将表达式树转换为 SQL 以及 SQL 服务器如何优化结果查询。

var vmlist = scaninfo.SelectMany(a => a.VMList).ToList();

这将运行 SQL 查询以获取与ScanInfo行关联的每个VMList行,为每个行构建一个 VMList 对象,然后在内存中创建一个列表来存储它们。

if (vmlist.Any(a2 => a2.Resource.RESOURCENAME.ToLower() == vmname.ToLower()))

这将贯穿该列表,并为每个项目计算出Resource.RESOURCENAME.ToLower() == vmname.ToLower()是否为真(不记住vmname.ToLower()的值(,并在找到匹配项后立即返回 true,如果从未找到匹配项,则返回 false。

if (scaninfo.Any(a=>a.VMList.Any(a2 => a2.Resource.RESOURCENAME.ToLower() == vmname.ToLower())))

这将对数据库运行EXISTS SQL 查询,并相应地返回truefalse

我们通常希望这会快得多,并且肯定会使用更少的内存。

查看 Enumerable.cs 的源代码,Any 定义为:

public static bool Any<TSource>(this IEnumerable<TSource> source, Func<TSource, bool> predicate) {
    if (source == null) throw Error.ArgumentNull("source");
    if (predicate == null) throw Error.ArgumentNull("predicate");
    foreach (TSource element in source) {
        if (predicate(element)) return true;
    }
    return false;
}

和 Select 及其对 SelectIterator 的调用是:

public static IEnumerable<TResult> Select<TSource, TResult>(this IEnumerable<TSource> source, Func<TSource, int, TResult> selector) {
    if (source == null) throw Error.ArgumentNull("source");
    if (selector == null) throw Error.ArgumentNull("selector");
    return SelectIterator<TSource, TResult>(source, selector);
}
 static IEnumerable<TResult> SelectIterator<TSource, TResult>(IEnumerable<TSource> source, Func<TSource, int, TResult> selector) {
    int index = -1;
    foreach (TSource element in source) {
        checked { index++; }
        yield return selector(element, index);
    }
}

因此,它们的执行方式不同,但通过查看 LINQ 表达式,它们的计算结果相同。