i measuring differences in query execution , stumbled upon case have no explanation for. query should retrieve 10000 customers main address (a customer can have many addresses). used 2 different methods navigation properties differ in execution time.
the first method retrieves customers way write linq queries: write results directly business object , calling tolist(). method takes 25 seconds execute.
the second method retrieves customers list of ef entities first. ef entities converted business objects in foreach loop. method takes 2 seconds execute.
can explain difference? , possible modify first method execution time similar second?
private list<icustomer> navigationproperties_so(int method) { using (entities context = new entities()) { context.database.log = s => system.diagnostics.debug.writeline(s); context.configuration.proxycreationenabled = false; context.configuration.autodetectchangesenabled = false; list<icustomer> customerlist = new list<icustomer>(); if (method == 1) { // execution time: 25 seconds customerlist = (from c in context.cust .include(o => o.addresslist) .include(o => o.addresslist.select(p => p.addr)) let mainaddress = c.addresslist.where(o => o.main_addr == "1").firstordefault() select new customer { cust = c, mainaddress = mainaddress, addr = mainaddress == null ? null : mainaddress.addr }).asnotracking().tolist<icustomer>(); } else if (method == 2) { // execution time: 2 seconds var templist = (from c in context.cust .include(o => o.addresslist) .include(o => o.addresslist.select(p => p.addr)) select c).asnotracking().tolist(); foreach (var c in templist) { icustomer customer = new customer(); var mainaddress = c.addresslist.where(o => o.main_addr == "1").firstordefault(); customer.cust = c; customer.mainaddress = mainaddress; customer.addr = mainaddress == null ? null : mainaddress.addr; customerlist.add(customer); } } return customerlist; } } edit
here (simplified) queries generated entity framework:
method 1
select * [dba].[cust] [extent1] outer apply (select top ( 1 ) * [dba].[cust_addr] [extent2] (([extent1].[id] = [extent2].[id]) , (n'1' = [extent2].[main_addr]) order 'a' ) [limit1] left outer join [dba].[addr] [extent3] on [limit1].[id] = [extent3].[id] method 2
select * ( select * [dba].[cust] [extent1] left outer join (select * [dba].[cust_addr] [extent2] left outer join [dba].[addr] [extent3] on [extent2].[id] = [extent3].[id] ) [join1] on ([extent1].[id] = [join1].[id]) ) [project1] the difference first method filtering in query (´let´) while second method retrieves records , filters in loop.
i suspect
let mainaddress = c.addresslist.where(o => o.main_addr == "1").firstordefault() is culprit. queries forces ef ask possible combinations returned. ef spends little time narrowing down scope before provides reasonable result set. can use sql server profiler @ queries generated.
in case, can use linq, rather foreach, @ end of second method (this won't performance, readability might improve):
return templist.select(c => new customer{cust=c, mainaddress = c.addresslist.firstordefault(o=>o.main_addr=="1"), ...);
Comments
Post a Comment