enterprise library - Why is reading a Dapper IEnumerable(dynamic) an order of magnitude slower than reading an IEnumerable(IDataRecord)? -
in comparing dapper enterprise library data access access block getting data via stored procedure. see overall performance benefit of 40% when using dapper, surprising.
however, when comparing iteration , getting data ienumerable(idatarecord) vs. ienumerable(dynamic), ienumerable(idatarecord) approximately order of magnitude faster. behavior understood , expected or there not right here?
the results:
ienumerable(idatarecord)
ienumerable(dynamic) - using dapperobject.propertyname
now interesting part, when using dapperobject["propertyname"], performance on par idatarecord. not @ have expected.
the relevant portion of profiling code
using system; using system.collections.generic; using system.linq; using dapper.dataaccess; using system.data; using tophat; namespace dapper.testrunner { class program { static void main(string[] args) { var connectionstring = "data source=webdbdev3,1866; user id=hsbmhw;password=gener4y&m;persist security info='true'; initial catalog=myhomeworks;"; //the following uses tophat create singleton connection instance. database.install<sqlserverconnectionfactory>(connectionstring, connectionscope.byrequest); dappertest(); dappertest2(); enterpriselibraryidatarecordtest(); } private static void dappertest() { (int = 0; < 100; i++) { ienumerable<dynamic> users = myrepository.getusersdapper(); populatebusinessobjectsdynamic(users); } } private static void dappertest2() { (int = 0; < 100; i++) { ienumerable<dynamic> users = myrepository.getusersdapper(); populatebusinessobjectsdynamic2(users); } } private static void enterpriselibraryidatarecordtest() { (int = 0; < 100; i++) { ienumerable<idatarecord> users = myrepository.getusersentlib(); populatebusinessobjectsidatarecord(users); } } private static void populatebusinessobjectsdynamic(ienumerable<dynamic> users) { foreach (var user in users) { businessobject bo = new businessobject(user); } } private static void populatebusinessobjectsdynamic2(ienumerable<dynamic> users) { foreach (var user in users) { businessobject bo = new businessobject(user); } } private static void populatebusinessobjectsidatarecord(ienumerable<idatarecord> users) { foreach (var user in users) { businessobject bo = new businessobject(user); } } } public class businessobject { public datetime createdate { get; set; } public string createdatestring { get; set; } public string firstname { get; set; } public bool isapproved { get; set; } public bool islockedout { get; set; } public datetime lastactivitydate { get; set; } public datetime lastlogindate { get; set; } public string lastname {get;set;} public string organization{get;set;} public int organizationid{get;set;} public int personid{get;set;} public string profilelastupdatedby{get;set;} public datetime profilelastupdateddate{get;set;} public string rolename{get;set;} public long rownumber{get;set;} public int totalcount{get;set;} public guid userid{get;set;} public string username {get;set;} public string userstatus{get;set;} public businessobject(dynamic user) { createdate=user.createdate; createdatestring = user.createdatestring; firstname = user.firstname; isapproved = user.isapproved; islockedout = user.islockedout; lastactivitydate= user.lastactivitydate; lastlogindate = user.lastlogindate; lastname = user.lastname; organization = user.organization; organizationid=user.organization_id; personid = user.party_id; profilelastupdatedby = user.profilelastupdatedby; profilelastupdateddate = user.profilelastupdateddate; rolename = user.rolename; rownumber = user.rownumber; totalcount = user.totalcount; userid = user.userid; username= user.username; userstatus = user.userstatus; } public businessobject(bool x, dynamic user) { createdate = user["createdate"]; createdatestring = user["createdatestring"]; firstname = user["firstname"]; isapproved = user["isapproved"]; islockedout = user["islockedout"]; lastactivitydate = user["lastactivitydate"]; lastlogindate = user["lastlogindate"]; lastname = user["lastname"]; organization = user["organization"]; organizationid = user["organization_id"]; personid = user["party_id"]; profilelastupdatedby = user["profilelastupdatedby"]; profilelastupdateddate = user["profilelastupdateddate"]; rolename = user["rolename"]; rownumber = user["rownumber"]; totalcount = user["totalcount"]; userid = user["userid"]; username = user["username"]; userstatus = user["userstatus"]; } public businessobject(idatarecord user) { createdate = (datetime)user["createdate"]; createdatestring = (string)user["createdatestring"]; firstname = (string)user["firstname"]; isapproved = (bool)user["isapproved"]; islockedout = (bool)user["islockedout"]; lastactivitydate = (datetime)user["lastactivitydate"]; lastlogindate = (datetime)user["lastlogindate"]; lastname = (string)user["lastname"]; organization = (string)user["organization"]; organizationid = (int)user["organization_id"]; personid = (int)user["party_id"]; profilelastupdatedby = (string)user["profilelastupdatedby"]; profilelastupdateddate = (datetime)user["profilelastupdateddate"]; rolename = (string)user["rolename"]; rownumber = (long)user["rownumber"]; totalcount = (int)user["totalcount"]; userid = (guid)user["userid"]; username = (string)user["username"]; userstatus = (string)user["userstatus"]; } } }
you seem running same test twice; input (users
) same, here:
private static void dappertest() { (int = 0; < 100; i++) { ienumerable<dynamic> users = myrepository.getusersdapper(); populatebusinessobjectsdynamic(users); } } private static void dappertest2() { (int = 0; < 100; i++) { ienumerable<dynamic> users = myrepository.getusersdapper(); populatebusinessobjectsdynamic2(users); } }
and actual "what do" same, here:
private static void populatebusinessobjectsdynamic(ienumerable<dynamic> users) { foreach (var user in users) { businessobject bo = new businessobject(user); } } private static void populatebusinessobjectsdynamic2(ienumerable<dynamic> users) { foreach (var user in users) { businessobject bo = new businessobject(user); } }
so... have conclude "a combination of jit, data caching (at database server) assembly loading/validation/fusion, connection pooling, , dynamic
cache features made second test appear faster".
note dynamic
side of dapper intended ad-hoc usage anyway. if wanted optimal face of dapper, use query<t>
, not dynamic
.
in particular, afaik no build of dapper supports string indexer on dynamic
api. object implements idictionary<string,object>
member access, need explicitly cast use - can't user["propname"]
if user
typed dynamic
(if i'm wrong, please tell me!).
as happens, unreleased "git" code (for dynamic
api) noticeably faster current "nuget" implementation - bit of tangent specific question.
Comments
Post a Comment