Performance Issues When Using Let in LINQ
Let is a powerful keyword in LINQ which allows us to assign a value to a temporary variable which can be reused in the LINQ statement. However, there can be performance penalties for using Let incorrectly.
Examples of Using Let in LINQ
static void TestBaseline()
{
var q = from c in Customer.AllCustomers
select c;
int count = q.Count();
}
static void TestWithAllocation()
{
var q = from c in Customer.AllCustomers
select new Customer() { CustomerID = c.CustomerID, CompanyName = c.CompanyName,
ContactName = c.ContactName, ContactTitle = c.ContactTitle,
Address = c.Address, City = c.City, Country = c.Country };
int count = q.Count();
}
static void TestWithSingleLet()
{
var q = from c in Customer.AllCustomers
let customerId = c.CustomerID
select new Customer() { CustomerID = customerId, CompanyName = c.CompanyName,
ContactName = c.ContactName, ContactTitle = c.ContactTitle,
Address = c.Address, City = c.City, Country = c.Country };
int count = q.Count();
}
static void TestWithMultipleLet()
{
var q = from c in Customer.AllCustomers
let customerId = c.CustomerID
let companyName = c.CompanyName
let contactName = c.ContactName
let contactTitle = c.ContactTitle
let address = c.Address
let city = c.City
let country = c.Country
select new Customer() { CustomerID = customerId, CompanyName = companyName,
ContactName = contactName, ContactTitle = contactTitle,
Address = address, City = city, Country = country };
int count = q.Count();
}
The first of these tests is a simple count over a list of customers. The second adds in an allocation for comparison with the other tests. The third test adds a single let statement, and the final test goes all out with let statements to exaggerate the effect. I have deliberately kept the tests simple (e.g. avoided group by/where statements) to maximize the effect of the let statement in each case. I ran each test 10,000 times and had the following results:
| Test | Time per test (ms) |
| TestBaseLine | 0.0051 |
| TestWithAllocation | 0.0085 |
| TestSingleLet | 0.0155 |
| TestMultipleLet | 0.0640 |
Comparing the test with allocation to the test with the multiple let statements, there is clearly an overhead to using the let keyword, but bear in mind that these tests have been designed to emphasise the effects of using let. Real-world queries are likely to include filtering/grouping etc that will diminish the relative effect of using let. Also, even with seven let keywords the query time is measured in hundreths of a millisecond.
The let keyword can also be used to increase performance. Suppose you have a value that is relatively expensive to calculate, but that needs to appear in the where clause multiple times:
static decimal SumOrders(Customer customer)
{
var q = from order in customer.Orders
from Order_Detail orderDetail in order.Order_Details
select orderDetail.Quantity * orderDetail.UnitPrice;
GC.KeepAlive(q);
return q.Sum();
}
static void CalcNoLet()
{
var q = from c in AllCustomers
where SumOrders(c) < 10000 && SumOrders(c) > 1000
select c;
int count = q.Count();
}
static void CalcWithLet()
{
var q = from c in AllCustomers
let expensiveValue = SumOrders(c)
where expensiveValue < 10000 && expensiveValue > 100
select c;
int count = q.Count();
}
Advertisement
In this example, we're summing the total value of the orders for each customer and only want customers where this value is between 1,000 and 10,000. Without let, this value gets calculated twice for each customer. We can use let to effectively give us query-local storage for the calculation so that it only performs the calculation once per customer. The results for these two queries are:
| Test | Time per test (ms) |
| CalcNoLet | 0.9387 |
| CalcWithLet | 0.7352 |
The results show that, in this case, the cost of performing the calculation outweighs the cost of the extra query that is generated by the let statement. So despite the addition of the extra query, using let reduces the query execution time.
Visit the LINQ Exchange Forum to post your comments, questions, or suggestions.
loading...
loading...
No related posts.
Related posts brought to you by Yet Another Related Posts Plugin.
