使用内部 .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())))
或者它们将以不同的方式执行?
谢谢
第一个选项有一个昂贵的操作,即使用 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 查询,并相应地返回true
或false
。
我们通常希望这会快得多,并且肯定会使用更少的内存。
查看 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 表达式,它们的计算结果相同。
呵呵