Я создал следующий тестовый пример в LINQPad.
void Main()
{
var listOfObjects = Enumerable.Range(0, 100000).Select(x => new TestClass() { SomeProperty = x.ToString() }).ToArray();
var iterations = DateTime.UtcNow.Day * 50;
Console.WriteLine("Doing {0} iterations", iterations);
var sw = Stopwatch.StartNew();
for(int i = 0; i < iterations; i++)
{
var filteredList = listOfObjects.Where(x => x.SomeProperty.Contains('0') && x.SomeProperty.Contains('1')).ToArray();
}
sw.Stop();
Console.WriteLine(sw.ElapsedMilliseconds);
sw.Reset();
sw.Start();
for(int i = 0; i < iterations; i++)
{
var filteredList = listOfObjects.Where(x => x.SomeProperty.Contains('0')).Where(x => x.SomeProperty.Contains('1')).ToArray();
}
sw.Stop();
Console.WriteLine(sw.ElapsedMilliseconds);
}
public class TestClass
{
public string SomeProperty { get; set; }
public string SomeOtherProperty { get; set; }
}
Для следующих 1350 итераций он дает следующие результаты.
- Для пункта
&&
, 19415 мс
- Для двух
Where
статей, 19596 мс
Это показывает, что первый из них чуть-чуть быстрее. Это может быть просто компилятор, делающий магию за кулисами, но, вычисляя список TestClass
, а также количество итераций во время выполнения, он не сможет ничего сделать.
Чтобы убедиться в фактическом SQL, вы должны взглянуть на IL, но на основе моего, похоже, что эффективный код идентичен.
<Main>b__2:
IL_0000: ldarg.0
IL_0001: callvirt UserQuery+TestClass.get_SomeProperty
IL_0006: ldc.i4.s 30
IL_0008: call System.Linq.Enumerable.Contains
IL_000D: brfalse.s IL_001E
IL_000F: ldarg.0
IL_0010: callvirt UserQuery+TestClass.get_SomeProperty
IL_0015: ldc.i4.s 31
IL_0017: call System.Linq.Enumerable.Contains
IL_001C: br.s IL_001F
IL_001E: ldc.i4.0
IL_001F: nop
IL_0020: stloc.0 // CS$1$0000
IL_0021: br.s IL_0023
IL_0023: ldloc.0 // CS$1$0000
IL_0024: ret
<Main>b__3:
IL_0000: ldarg.0
IL_0001: callvirt UserQuery+TestClass.get_SomeProperty
IL_0006: ldc.i4.s 30
IL_0008: call System.Linq.Enumerable.Contains
IL_000D: stloc.0 // CS$1$0000
IL_000E: br.s IL_0010
IL_0010: ldloc.0 // CS$1$0000
IL_0011: ret
<Main>b__4:
IL_0000: ldarg.0
IL_0001: callvirt UserQuery+TestClass.get_SomeProperty
IL_0006: ldc.i4.s 31
IL_0008: call System.Linq.Enumerable.Contains
IL_000D: stloc.0 // CS$1$0000
IL_000E: br.s IL_0010
IL_0010: ldloc.0 // CS$1$0000
IL_0011: ret
Предложение Where
, который использует &&
это первый бит IL, показывая два вызова Contains
в анонимном методе. Тест, который использует предложение double Where
, вызывает два разных анонимных метода, однако они кажутся одинаковыми, за исключением параметра, переданного в Contains
. Рассматривая основной метод, мы можем видеть сделанные вызовы и видеть, что накладные расходы минимальны. Это приводит к чуть более медленному коду при использовании двух статей Where
.
Мое предложение - запустить тест (например, кодированный выше) против фактической базы данных SQL и посмотреть, как выглядит производительность. Сгенерированный ИЛ может быть почти идентичным, но при переходе на SQL может существенно отличаться.
ориентир и дайте нам знать? –
Вы можете посмотреть запросы и сами убедиться, добавив обработчик для 'context.Database.Log'. –
Возможный дубликат [Proper Linq where clauses] (http://stackoverflow.com/questions/6359980/proper-linq-where-clauses) – Jonesopolis