왜 Dapper IEnumerable (동적)을 IEnumerable (IDataRecord)를 읽는 것보다 느리게 읽는 것이 더 빠릅니까?

dapper enterprise-library

문제

Dapper와 저장 프로 시저를 통해 데이터를 가져 오기위한 엔터프라이즈 라이브러리 데이터 액세스 액세스 블록 비교. Dapper를 사용할 때 전반적인 성능 이점이 약 40 %라는 것을 알았습니다. 다소 놀라운 것입니다.

그러나 반복을 비교하고 IEnumerable (IDataRecord) 대 IEnumerable (동적)의 데이터를 가져올 때 IEnumerable (IDataRecord)은 약 1 배 정도 빠릅니다. 이 행동을 잘 이해하고 있으며 기대 되는가 아니면 여기에 뭔가가 있습니까?

결과 :

IEnumerable (IDataRecord) 여기에 이미지 설명을 입력하십시오.

IEnumerable (동적) - dapperObject.propertyName 사용 여기에 이미지 설명을 입력하십시오.

이제 흥미로운 점은 dapperObject [ "propertyName"]을 사용할 때 성능이 IDataRecord와 동등한 것입니다. 전혀 기대하지 않았던 것. 여기에 이미지 설명을 입력하십시오.

프로파일 링 코드의 관련 부분

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 to create a singleton connection instance.
            Database.Install<SqlServerConnectionFactory>(connectionString, ConnectionScope.ByRequest);
            DapperTest();
            DapperTest2();
            EnterpriseLibraryIDataRecordTest();

        }

        private static void DapperTest()
        {
            for (int i = 0; i < 100; i++)
            {
                IEnumerable<dynamic> users = MyRepository.GetUsersDapper();
                PopulateBusinessObjectsDynamic(users);
            }
        }

        private static void DapperTest2()
        {
            for (int i = 0; i < 100; i++)
            {
                IEnumerable<dynamic> users = MyRepository.GetUsersDapper();
                PopulateBusinessObjectsDynamic2(users);
            }
        }

        private static void EnterpriseLibraryIDataRecordTest()
        {
            for (int i = 0; i < 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"];
        }
    }
}

수락 된 답변

실제로 동일한 테스트를 두 번 실행하는 것 같습니다. 입력 ( users )은 여기에서 동일합니다.

    private static void DapperTest()
    {
        for (int i = 0; i < 100; i++)
        {
            IEnumerable<dynamic> users = MyRepository.GetUsersDapper();
            PopulateBusinessObjectsDynamic(users);
        }
    }

    private static void DapperTest2()
    {
        for (int i = 0; i < 100; i++)
        {
            IEnumerable<dynamic> users = MyRepository.GetUsersDapper();
            PopulateBusinessObjectsDynamic2(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);
        }
    }

그래서 ... "JIT, 데이터 캐싱 (데이터베이스 서버에서) 어셈블리 로딩 / 유효성 검사 / 융합, 연결 풀링 및 dynamic 캐시 기능의 결합으로 두 번째 테스트가 더 빨리 수행되어야합니다"라고 결론 내어야합니다.

dapper의 dynamic 측면은 어쨌든 임시 용도로만 사용됩니다. 만약 당신이 dapper의 최적의 얼굴을 원한다면, dynamic 아닌 Query<T> 사용할 것입니다.

특히, AFAIK는 dapper를 빌드하지 않아도 dynamic API에서 문자열 인덱서를 지원 합니다. 객체는 멤버 액세스를 위해 IDictionary<string,object> 를 구현하지만이를 사용하려면 명시 적으로 캐스팅해야합니다. userdynamic 으로 입력 된 경우 user user["PropName"] 수행 할 수 없습니다. 나에게 말해주세요!).

결과적으로, 출시되지 않은 "git"코드 ( dynamic API의 경우)는 현재의 "누겟"구현보다 눈에 띄게 빠르지 만 이는 특정 질문에 약간의 접선입니다.



아래 라이선스: CC-BY-SA with attribution
와 제휴하지 않음 Stack Overflow
이 KB는 합법적입니까? 예, 이유를 알아보십시오.
아래 라이선스: CC-BY-SA with attribution
와 제휴하지 않음 Stack Overflow
이 KB는 합법적입니까? 예, 이유를 알아보십시오.