Entity Framework는 트래픽이 많은 웹 사이트에 적합합니까?


176

Entity Framework 4는 잠재적으로 초당 적중 횟수가 1000 인 공개 웹 사이트에 적합한 솔루션입니까?

내 이해에 따르면 EF는 주로 소규모 또는 인트라넷 웹 사이트에 적합한 솔루션이지만 인기있는 커뮤니티 웹 사이트와 같이 쉽게 확장 할 수는 없습니다 (SOQ는 LINQ to SQL을 사용하고 있지만 .. 더 많은 예제 / 증거를 원합니다. ..)

이제 순수한 ADO.NET 접근 방식 또는 EF4를 선택하는기로에 서 있습니다. EF를 통해 향상된 개발자 생산성이 성능 저하 및 ADO.NET의 세분화 된 액세스 (저장 프로 시저 사용)에 대한 가치가 있다고 생각하십니까? 트래픽이 많은 웹 사이트가 직면 할 수있는 심각한 문제는 EF를 사용 했습니까?

미리 감사드립니다.


1
스케일링을 이해하지 못합니다. 확장은 10 배의 용량을 추가 할 때 10 배의 처리량을 얻는 것을 의미합니다. EF가 왜 이런 일이 발생하지 않습니까? 모든 데이터베이스 워크로드에 일정한 요소 오버 헤드를 추가합니다.
usr

답변:


152

얼마나 많은 추상화 가 필요한지 에 따라 다릅니다 . 모든 것이 타협입니다. 예를 들어, EF와 NHibernate는 흥미롭고 이국적인 모델로 데이터를 표현할 수있는 뛰어난 유연성을 제공하지만 결과적으로 오버 헤드 추가됩니다. 눈에 띄는 오버 헤드.

데이터베이스 공급자와 다른 클라이언트 별 테이블 레이아웃간에 전환 할 필요 가없고 데이터를 주로 읽는 경우 및 EF에서 동일한 모델을 사용할 필요가없는 경우 SSRS , ADO.NET 데이터 서비스 등-주요 측정 값으로 절대 성능을 원하면 dapper를 보는 것보다 훨씬 나빠질 수 있습니다. LINQ-to-SQL 및 EF를 기반으로 한 테스트 에서 추상화 계층 (스토리지 모델 등)과 구체화로 인해 원시 읽기 성능 측면에서 EF가 상당히 느리다 는 것을 알 수 있습니다.

여기서 우리는 원시 성능에 대해 강박 관념을 가지고 있으며 속도를 얻기 위해 추상화를 잃어 버린 개발 히트를 기뻐합니다. 따라서 데이터베이스 쿼리를위한 기본 도구는 dapper 입니다. 이를 통해 기존의 LINQ-to-SQL 모델을 사용할 수도 있지만 단순히 힙이 더 빠릅니다. 성능 테스트에서는 기본적으로 모든 ADO.NET 코드 (매개 변수, 데이터 판독기 등)를 수동으로 작성하는 것과 동일한 성능이지만 열 이름이 잘못 될 위험이 없습니다. 그러나 SQL 기반입니다 (선택한 독인 경우 SPROC를 사용하는 것이 좋지만). 이것의 장점은 없다는 것입니다 추가 처리 관련, 그러나 그것은 이다 SQL을 좋아하는 사람들을위한 시스템. 내가 생각하는 것 : 나쁜 것은 아니다!

예를 들어 일반적인 쿼리는 다음과 같습니다.

int customerId = ...
var orders = connection.Query<Order>(
    "select * from Orders where CustomerId = @customerId ",
    new { customerId }).ToList();

그것은 편리하고 주입 안전합니다-그러나 많은 데이터 리더 goo가 없습니다. 수평 및 수직 파티션을 모두 처리하여 복잡한 구조를로드 할 수는 있지만 지연 로딩을 지원하지는 않습니다 (그러나 우리는 매우 명백한 로딩의 팬입니다.

이 답변에서 저는 EF 대량 작업에 적합 하지 않다는 말을 하지 않습니다 . 간단히 : 나는 dapper가 그에 달려 있음을 알고 있습니다.


25
dapper의 경우 +1 읽기 모델에 복잡한 ORM을 사용하는 것은 불필요합니다. 지금 우리가 취하는 접근 방식은 도메인 모델에 ORM을 사용하고 (멋진 ORM이 실제로 유용한 경우) 읽기 모델에 dapper를 사용하는 것입니다. 이것은 매우 빠른 응용 프로그램을 만듭니다.

2
@Marc, 훌륭한 답변에 감사드립니다. 마침내 자신있게 결정을 내릴 수 있습니다! 나중에 dapper를 자세히 살펴볼 것입니다. 정말 그것은 단지 하나 개의 파일 : 얼마나 좋아

3
나는 내 자신의 ORM을 작성했습니다. 느리다. 나는 dapper를보고 좋아했습니다. 이제 모든 읽기에 dapper를 사용하고 삽입에 FOR, 트랜잭션 및 모든 좋은 것을 지원하는 ORM에 ORM을 사용합니다. 내가 작성한 가장 쉬운 코드입니다.

2
@ acidzombie24 dapper는 트랜잭션을 지원하며 dapper의 contrib 부분 (nuget 배포의 일부는 아님)이 insert etc 옵션을 얻고 있습니다. 완전성을 언급하는 것뿐입니다. dapper가 편리해서 다행입니다.
Marc Gravell

1
@anyname 나는 어떤 주제에 대해서도 비디오 강의를 한 적이 없다. 저 밖에없는 비디오가 있습니다. 나는 글을 쓰는 사람인 경향이있다
Marc Gravell

217

"어떤 ORM을 사용해야합니까?"라는 질문은 대규모 응용 프로그램의 전반적인 데이터 액세스 전략 및 성능 최적화와 관련하여 실제로 거대한 빙산의 일각을 목표로합니다.

다음의 모든 것 ( 대략 중요한 순서로)은 처리량에 영향을 미치며 모든 주요 ORM 프레임 워크에서 처리됩니다 (때로는 다른 방식으로 처리됨).

  1. 데이터베이스 설계 및 유지 관리

    이는 데이터 중심 응용 프로그램 또는 웹 사이트의 처리량을 결정하는 가장 중요한 요소 중 하나이며, 프로그래머는이를 완전히 무시합니다.

    적절한 정규화 기술을 사용하지 않으면 사이트가 파기됩니다. 기본 키가 없으면 거의 모든 쿼리가 느리게 진행됩니다. 정당한 이유없이 키-값 쌍 (AKA Entity-Attribute-Value)에 테이블을 사용하는 등 잘 알려진 안티 패턴을 사용하는 경우 물리적 읽기 및 쓰기 수를 확장합니다.

    페이지 압축, FILESTREAM스토리지 (이진 데이터의 경우), SPARSE열, hierarchyid계층의 경우 등 (모든 SQL Server 예) 과 같이 데이터베이스가 제공하는 기능을 활용하지 않으면 당신 있는 성능 .

    데이터베이스를 설계 한 후 최소한 당분간은 그것이 가능한 한 좋다는 것을 확신 한 후에 데이터 액세스 전략에 대해 걱정해야합니다 .

  2. 열성 대 지연 로딩

    대부분의 ORM 은 관계에 지연로드 ( lazy loading) 라는 기술을 사용했습니다. 즉, 기본적으로 한 번에 하나의 엔티티 (테이블 행)를로드하고 하나 이상의 관련 (외부)을로드해야 할 때마다 데이터베이스를 왕복합니다. 키) 행.

    이것은 좋지 않거나 나쁜 것이 아니라 실제로 데이터로 수행 할 작업과 사전에 얼마나 많이 알고 있는지에 달려 있습니다. 때로는 게으른 로딩이 절대적으로 올바른 일입니다. 예를 들어 NHibernate 는 전혀 쿼리하지 않고 특정 ID에 대한 프록시 를 생성 하기로 결정할 수 있습니다 . ID 만 필요한 경우 왜 더 요청해야합니까? 반면에 3 단계 계층 구조에서 모든 단일 요소의 트리를 인쇄하려고하면 지연로드가 O (N²) 연산이 되어 성능 이 매우 나빠집니다.

    "순수한 SQL"(즉, 원시 ADO.NET 쿼리 / 저장 프로 시저)을 사용하면 흥미로운 이점 중 하나는 기본적으로 주어진 화면이나 페이지를 표시하는 데 필요한 데이터를 정확히 생각하게한다는 것입니다. 으로 ORMs 게으른 로딩 기능을하지 않도록 이 일에서 당신을, 그러나 그들은 않는 당신에게 잘 ... 할 수있는 기회 제공 지연 및 실수로 실행 쿼리 수를 폭발합니다. 따라서 ORM의 열성적인 로딩 기능을 이해하고 주어진 페이지 요청에 대해 서버로 전송하는 쿼리 수에주의를 기울여야합니다.

  3. 캐싱

    모든 주요 ORM은 첫 번째 수준 캐시 인 "일명 캐시"를 유지합니다. 즉, 동일한 엔터티를 ID로 두 번 요청하면 두 번째 왕복이 필요하지 않으며 데이터베이스를 올바르게 설계 한 경우 )를 사용하면 낙관적 동시성을 사용할 수 있습니다.

    L1 캐시는 L2S 및 EF에서 매우 불투명하므로 작동하고 있다는 것을 신뢰해야합니다. NHibernate는 그것에 대해 더 명확합니다 ( Get/ Loadvs. Query/ QueryOver). 그럼에도 불구하고 가능한 한 ID로 쿼리하려고 시도하는 한 여기에 좋습니다. 많은 사람들이 L1 캐시를 잊어 버리고 ID 이외의 다른 항목 (예 : 조회 필드)을 통해 동일한 엔티티를 반복해서 반복해서 찾습니다. 이 작업을 수행해야 할 경우 향후 조회를 위해 ID 또는 전체 엔티티를 저장해야합니다.

    레벨 2 캐시 ( "쿼리 캐시")도 있습니다. NHibernate는이 기능을 내장하고 있습니다. Linq to SQL 및 Entity Framework는 쿼리 를 컴파일하여 쿼리 표현식 자체를 컴파일하여 앱 서버로드를 상당히 줄일 수 있지만 데이터를 캐시하지는 않습니다. Microsoft는이를 데이터 액세스 문제가 아니라 응용 프로그램 문제로 간주하는 것 같습니다. 이는 L2S와 EF의 주요 단점입니다. "raw"SQL의 약점이기도합니다. 기본적으로 NHibernate 이외의 다른 ORM으로 좋은 성능을 얻으려면 자체 캐싱 외관을 구현해야합니다.

    이 EF4에 대한 L2 캐시 "확장자"이기도 괜찮는 응용 프로그램 수준의 캐시 도매 교체는 정말 아니지만.

  4. 쿼리 수

    관계형 데이터베이스는 데이터 세트 를 기반으로 합니다 . 짧은 시간에 많은 양의 데이터 를 생성하는 데 능숙 하지만 모든 명령에 일정한 양의 오버 헤드가 있기 때문에 쿼리 대기 시간 측면에서 거의 없습니다 . 잘 설계된 앱은이 DBMS의 장점을 활용하고 쿼리 수를 최소화하고 각각의 데이터 양을 최대화해야합니다.

    이제 하나의 행만 필요할 때 전체 데이터베이스를 쿼리한다고 말하지 않습니다. 당신이 필요로하는 경우 어떤 말인지이다 Customer, Address, Phone, CreditCard, 그리고 Order당신이해야 한 페이지를 제공하기 위해 동시에 행을 모두 에게 동시에 그들 모두에 대해 개별적으로 각 쿼리를 실행하지 않습니다. 때로는 그보다 더 나쁜 경우가 있습니다. 먼저 같은 Customer레코드를 5 번 연속으로 쿼리하는 코드가 먼저 표시되고 Id, 그 다음에 Name, 그 다음에 EmailAddress.

    모두 완전히 다른 데이터 집합에서 작동하는 여러 쿼리를 실행해야하는 경우에도 단일 "스크립트"로 데이터베이스에 모든 쿼리를 보내고 여러 결과 집합을 반환하는 것이 여전히 더 효율적입니다. 총 데이터 양이 아니라 관련된 오버 헤드입니다.

    이것은 상식처럼 들릴지 모르지만 응용 프로그램의 다양한 부분에서 실행되는 모든 쿼리를 추적하기가 쉽지 않습니다. 멤버 자격 공급자가 사용자 / 역할 테이블을 쿼리하고, 헤더 작업이 쇼핑 카트를 쿼리하고, 메뉴 작업이 사이트 맵 테이블을 쿼리하고, 사이드 바 작업이 주요 제품 목록을 쿼리 한 다음 페이지가 몇 개의 개별 자율 영역으로 나뉩니다. 주문 내역, 최근 본 항목, 카테고리 및 인벤토리 테이블을 개별적으로 쿼리하고 알기 전에 페이지를 제공하기 전에 20 개의 쿼리를 실행하고 있습니다. 그것은 단지 성능을 완전히 파괴합니다.

    NHibernate를 중심으로 생각하는 일부 프레임 워크는 이것에 대해 매우 영리 하며 전체 쿼리를 일괄 처리하고 마지막 순간에 한 번에 모두 실행하려고하는 미래 라는 것을 사용할 수 있습니다 . AFAIK, Microsoft 기술로이 작업을 수행하려는 경우 스스로해야합니다. 애플리케이션 로직에 빌드해야합니다.

  5. 인덱싱, 술어 및 프로젝션

    내가 말한 개발자의 50 % 이상, 심지어 일부 DBA조차도 인덱스 적용 개념에 문제가있는 것 같습니다. 그들은 " Customer.Name열이 색인화되어 있으므로 이름에 대한 모든 조회가 빠르다"고 생각합니다. 하지 않는 한 그런 식으로 작동하지 않는 경우를 제외 Name지수는 커버 당신이 찾고있는 특정 열을. SQL Server에서는 명령문 INCLUDE에서 수행됩니다 CREATE INDEX.

    SELECT *프로젝션을 사용하여 명시 적으로 지정하지 않는 한 모든 ORM이 수행하는 작업이 거의 모든 곳에서 순진하게 사용되는 경우 DBMS는 커버되지 않은 열을 포함하기 때문에 인덱스를 완전히 무시하도록 선택할 수 있습니다. 투영은 예를 들어 다음을 수행하는 대신 다음을 의미합니다.

    from c in db.Customers where c.Name == "John Doe" select c
    

    대신이 작업을 수행하십시오.

    from c in db.Customers where c.Name == "John Doe"
    select new { c.Id, c.Name }
    

    그리고이 뜻은, 가장 현대으로 ORMs을 위해, 그것은 단지 가서 조회하도록 지시 Id하고 Name아마도 인덱스에 포함되는 열 (그러나 Email, LastActivityDate또는 다른 무엇이든 당신이 거기에 붙어 일어난 열).

    부적절한 술어를 사용하여 인덱싱 이점을 완전히 없애는 것도 매우 쉽습니다. 예를 들면 다음과 같습니다.

    from c in db.Customers where c.Name.Contains("Doe")
    

    ... 이전 쿼리와 거의 동일 해 보이지만 실제로로 변환되기 때문에 전체 테이블 또는 인덱스 스캔이 발생합니다 LIKE '%Doe%'. 마찬가지로 의심스러운 것처럼 보이는 다른 쿼리는 다음과 같습니다.

    from c in db.Customers where (maxDate == null) || (c.BirthDate >= maxDate)
    

    에 인덱스가 있다고 가정하면 BirthDate이 술어는 인덱스를 완전히 쓸모 없게 만들 수 있습니다. 여기서 우리의 가상 프로그래머는 일종의 동적 쿼리 ( "해당 매개 변수가 지정된 경우 생년월일 만 필터링")를 작성하려고 시도했지만 이것이 올바른 방법은 아닙니다. 대신 이렇게 작성 :

    from c in db.Customers where c.BirthDate >= (maxDate ?? DateTime.MinValue)
    

    ... 이제 DB 엔진은이를 매개 변수화하고 인덱스 탐색을 수행하는 방법을 알고 있습니다. 쿼리 표현식에 대한 사소하고 미미한 변경이 성능에 크게 영향을 줄 수 있습니다.

    불행하게도 일반적으로 LINQ가 있기 때문에 모두가 너무 쉽게 이런 나쁜 쿼리를 작성 할 수 있습니다 때로는 공급자가 당신이 쿼리를 최적화하기 위해 노력하고 있었는지 추측 할 수 있으며, 때때로이 없습니다. 그래서 당신 은 평범한 오래된 SQL을 작성했다면 (어쨌든 숙련 된 DBA에게) 맹목적으로 명백했을 실망스러운 일관성없는 결과로 끝납니다 .

    기본적으로 모든 것은 생성 된 SQL과 그들이 생성 한 실행 계획을 모두 면밀히 관찰해야한다는 사실에 달려 있으며, 기대하는 결과를 얻지 못하면 무시하지 마십시오. 가끔 ORM 레이어를 작성하고 SQL을 직접 코딩하십시오. 이것은 EF뿐만 아니라 모든 ORM에 적용됩니다.

  6. 거래 및 잠금

    밀리 초까지 최신 데이터를 표시해야합니까? 어쩌면-그것은 달려 있지만-아마도 아닙니다. 슬프게도, 엔티티 프레임 워크를 제공하지 않습니다nolock 만 사용할 수 있습니다 READ UNCOMMITTED상기 트랜잭션 레벨 (안 테이블 수준). 실제로 어떤 ORM도 이에 대해 신뢰할만한 것은 없습니다. 더티 읽기를 수행하려면 SQL 레벨로 드롭 다운하고 임시 쿼리 또는 스토어드 프로 시저를 작성해야합니다. 다시 요약하자면 프레임 워크 내에서이를 수행하는 것이 얼마나 쉬운 지입니다.

    Entity Framework는 이와 관련하여 먼 길을 왔습니다. EF 버전 1 (.NET 3.5)은 신기한 것으로 "엔티티"추상화를 뚫기가 매우 어려웠지만 이제는 ExecuteStoreQueryTranslate 가 있으므로 실제로는 그렇습니다. 나쁘지 않아. 당신이 그들을 많이 사용하기 때문에이 사람들과 친구를 사귀십시오.

    쓰기 잠금 및 교착 상태 문제와 데이터베이스에서 잠금을 가능한 한 짧은 시간 동안 유지하는 일반적인 방법도 있습니다. 이와 관련하여, 대부분의 ORM (Entity Framework 포함)은 실제로 작업 단위 패턴 (EF에서 SaveChanges) 을 캡슐화하기 때문에 원시 SQL보다 나은 경향이 있습니다 . 다시 말해, 원할 때마다 엔티티를 "삽입"또는 "업데이트"또는 "삭제"하여 작업 단위를 커밋 할 때까지 변경 사항이 실제로 데이터베이스에 적용되지 않는다는 지식을 확보 할 수 있습니다.

    UOW는 장기 실행 트랜잭션과 유사 하지 않습니다 . UOW는 여전히 ORM의 낙관적 동시성 기능을 사용하고 메모리의 모든 변경 사항 추적합니다 . 최종 커밋까지 단일 DML 문이 생성되지 않습니다. 이것은 트랜잭션 시간을 가능한 한 낮게 유지합니다. 원시 SQL을 사용하여 애플리케이션을 빌드하는 경우이 지연된 동작을 달성하기가 매우 어렵습니다.

    이것이 EF의 구체적 의미 : 작업 단위를 가능한 한 굵게 만들고 절대적으로 필요할 때까지 커밋하지 마십시오. 이렇게하면 임의의 시간에 개별 ADO.NET 명령을 사용할 때보 다 잠금 경합이 훨씬 줄어 듭니다.

결론적으로:

EF는 다른 모든 프레임 워크가 트래픽 / 고성능 응용 프로그램에 적합 하듯이 트래픽 / 고성능 응용 프로그램에는 완벽하게 적합합니다. 중요한 것은 사용 방법입니다. 다음은 가장 널리 사용되는 프레임 워크와 성능 측면에서 제공하는 기능에 대한 간단한 비교입니다 (범례 : N = 지원되지 않음, P = 부분, Y = 예 / 지원됨).

                                | L2S | EF1 | EF4 | NH3 | ADO
                                +-----+-----+-----+-----+-----
Lazy Loading (entities)         |  N  |  N  |  N  |  Y  |  N
Lazy Loading (relationships)    |  Y  |  Y  |  Y  |  Y  |  N
Eager Loading (global)          |  N  |  N  |  N  |  Y  |  N
Eager Loading (per-session)     |  Y  |  N  |  N  |  Y  |  N
Eager Loading (per-query)       |  N  |  Y  |  Y  |  Y  |  Y
Level 1 (Identity) Cache        |  Y  |  Y  |  Y  |  Y  |  N
Level 2 (Query) Cache           |  N  |  N  |  P  |  Y  |  N
Compiled Queries                |  Y  |  P  |  Y  |  N  | N/A
Multi-Queries                   |  N  |  N  |  N  |  Y  |  Y
Multiple Result Sets            |  Y  |  N  |  P  |  Y  |  Y
Futures                         |  N  |  N  |  N  |  Y  |  N
Explicit Locking (per-table)    |  N  |  N  |  N  |  P  |  Y
Transaction Isolation Level     |  Y  |  Y  |  Y  |  Y  |  Y
Ad-Hoc Queries                  |  Y  |  P  |  Y  |  Y  |  Y
Stored Procedures               |  Y  |  P  |  Y  |  Y  |  Y
Unit of Work                    |  Y  |  Y  |  Y  |  Y  |  N

보시다시피, EF4 (현재 버전)는 그리 나쁘지 않지만 성능이 주요 관심사 인 경우 아마도 최고가 아닙니다. NHibernate는이 분야에서 훨씬 더 성숙하고 Linq to SQL조차도 EF가 아직 수행하지 못하는 성능 향상 기능을 제공합니다. Raw ADO.NET은 매우 구체적인 데이터 액세스 시나리오에서 종종 더 빠를 것이지만, 모든 부분을 종합하면 다양한 프레임 워크에서 얻을 수있는 많은 중요한 이점을 제공하지 않습니다.

그리고 내가 부러진 레코드처럼 들리도록하기 위해 데이터베이스, 응용 프로그램 및 데이터 액세스 전략을 제대로 설계하지 않으면 아무 문제가 없습니다. 위 차트의 모든 항목 은 기준을 넘어 성능 을 개선 하기 위한 것입니다 . 대부분의 경우 기준 자체가 가장 개선이 필요한 것입니다.


38
대단하고 포괄적 인 답변입니다!

2
+1 (가능한 경우 더)-여기에 내가 본 가장 좋은 답변 중 하나이며 한두 가지를 배웠습니다. 이것을 공유해 주셔서 감사합니다!
BrokenGlass

1
이것은 언급 한 모든 것에 동의하지 않아도 훌륭한 답변입니다. ORM을 비교하는 테이블이 항상 올바른 것은 아닙니다. 엔티티 지연 로딩이란 무엇입니까? 게으른로드 된 컬럼을 의미합니까? L2S에서 지원됩니다. NH가 컴파일 된 쿼리를 지원하지 않는 이유는 무엇입니까? 명명 된 HQL 쿼리를 미리 컴파일 할 수 있다고 생각합니다. EF4는 여러 결과 세트를 지원하지 않습니다.
Ladislav Mrnka

11
자격이없는 "EF는 트래픽이 많은 / 고성능 응용 프로그램에는 완벽하게 적합합니다"라는 말 에 강력하게 동의하지 않아야합니다. 물론, 우리는 "고성능"의 의미에 동의하지 않을 수 있지만, 예를 들어 웹 페이지를 500ms까지 최적화하고 프레임 워크 내에서 설명 할 수없는 400ms 이상 ( 실제로 SQL에 영향을주는 10ms 만 )이 일부 상황에서는 "정확하지 않음", 개발자 팀에게는 용납 할 수 없습니다.
Nick Craver

1
EF의 미래에 대한 간단한 메모. 이들은 공식적으로 MS EF 팀에서 제공하지는 않지만 Future <> IQueryable <> 확장을 정의하는 타사 프로젝트를 통해 달성 할 수 있습니다. 예를 들어 NuGet에서 사용 가능한 LoreSoft에 의해 확장 된 EntityFramework. 프로덕션 응용 프로그램의 개인 테스트에서는 Future를 사용하여 단일 배치로 수십 개의 비 종속 쿼리 (모든 쿼리를 병렬로 실행할 수 있으며 이전 쿼리의 결과는 필요하지 않음)를 포장 할 때 최대 10 배의 성능 향상을 보여줍니다. 또한 AsNoTracking ()은 많은 레코드를 읽을 때 성능을 크게 향상시키고 나중에 업데이트하지 않습니다.
David Oliván Ubieto

38

편집 : @Aaronaught 훌륭한 답변을 바탕으로 EF로 성능을 목표로하는 몇 가지 포인트를 추가하고 있습니다. 이 새로운 포인트 앞에는 편집이 있습니다.


트래픽이 많은 웹 사이트의 성능이 크게 향상되면 데이터베이스 쿼리가 수행되는 동안 스레드 차단을 피하기 위해 캐싱 (= 웹 서버 처리 또는 데이터베이스 쿼리 방지) 및 비동기 처리가 수행됩니다.

질문은 항상 응용 프로그램 요구 사항과 복잡한 쿼리에 따라 다르므로 질문에 대한 답은 없습니다. 사실 EF의 개발자 생산성은 복잡성을 숨겨 많은 경우 EF의 잘못된 사용과 끔찍한 성능으로 이어집니다. 데이터 액세스를 위해 높은 수준의 추상화 된 인터페이스를 노출 할 수 있으며 모든 경우에 원활하게 작동한다는 아이디어는 작동하지 않습니다. ORM을 사용하더라도 추상화 뒤에서 발생하는 상황과 올바르게 사용하는 방법을 알아야합니다.

EF에 대한 이전 경험이 없다면 성능을 다룰 때 많은 어려움을 겪게됩니다. ADO.NET과 비교하여 EF로 작업 할 때 훨씬 더 많은 실수를 할 수 있습니다. 또한 EF에는 추가 처리가 많이 있으므로 EF는 항상 기본 ADO.NET보다 상당히 느리게 진행됩니다. 즉, 간단한 개념 증명 응용 프로그램으로 측정 할 수 있습니다.

EF에서 최고의 성능을 얻으려면 다음을 수행해야합니다.

  • Linq-to-objects 대신 Linq-to-entities를 올바르게 사용하는 경우 SQL 프로파일 러를 사용하여 데이터 액세스를 매우 신중하게 수정하고 LINQ 쿼리를 검토하십시오.
  • 다음과 같은 고급 EF 최적화 기능을 매우 신중하게 사용하십시오. MergeOption.NoTracking
  • 경우에 따라 ESQL 사용
  • 자주 실행되는 사전 컴파일 쿼리
  • EF 캐싱 래퍼를 활용하여 일부 쿼리의 기능과 같은 "두 번째 수준 캐시"를 얻는 것을 고려하십시오.
  • 성능 향상이 필요한 자주 사용되는 프로젝션 또는 집계에 대해 일부 시나리오에서 SQL보기 또는 사용자 정의 맵핑 된 SQL 쿼리 (EDMX 파일의 수동 유지 보수 필요) 사용
  • Linq 또는 ESQL에 정의 된 경우 충분한 성능을 제공하지 않는 일부 쿼리에는 기본 SQL 및 저장 프로 시저를 사용하십시오.
  • 편집 : 조심스럽게 쿼리 사용-모든 쿼리는 데이터베이스에 대한 별도의 왕복을 만듭니다. EFv4는 실행 된 데이터베이스 명령 당 여러 결과 세트를 사용할 수 없으므로 쿼리 배치가 없습니다. EFv4.5는 매핑 저장 프로 시저에 대해 여러 결과 집합을 지원합니다.
  • 편집 : 데이터 수정 작업을 신중하게 수행 하십시오 . 다시 EF에는 명령 일괄 처리가 완전히 없습니다 . 따라서 ADO.NET에서는 SqlCommand다중 삽입, 업데이트 또는 삭제를 포함 하는 단일 을 사용할 수 있지만 EF를 사용하면 이러한 모든 명령이 데이터베이스에 대한 별도의 왕복으로 실행됩니다.
  • 편집 : 신원 맵 / 신원 캐시로 신중하게 작업 하십시오 . EF에는 캐시를 먼저 쿼리하는 특수 메소드 ( GetByKeyObjectContext API 또는 FindDbContext API)가 있습니다. Linq-to-entities 또는 ESQL을 사용하는 경우 데이터베이스에 대한 왕복을 작성하고 캐시에서 기존 인스턴스를 리턴합니다.
  • 편집 : 열성적인 로딩을 조심스럽게 사용 하십시오 . 하나의 거대한 데이터 세트를 생성하기 때문에 항상 상생 솔루션이 아닙니다 . 보시다시피 많은 추가 복잡성이 있으며 이것이 핵심입니다. ORM을 사용하면 매핑 및 구체화가 더 간단 해지지 만 성능을 처리 할 때는 훨씬 복잡 해져서 절충해야합니다.

SO가 여전히 L2S를 사용하고 있는지 잘 모르겠습니다. 그들은 Dapper 라고하는 새로운 오픈 소스 ORM을 개발 했으며이 개발의 주요 요점은 성능 향상이라고 생각합니다.


라디 슬라 프, 정말 유용한 답변입니다. 이것은 내가 Dapper (그리고 결과적으로 PetaPoco, Massive)를 처음봤을 때 흥미로운 아이디어 인 것 같습니다.

1
그래서 LINQ를 SQL과 Dapper에 혼합하여 사용하는 것 같습니다 : samsaffron.com/archive/2011/03/30/… 인용 : "특정 문제에 대해 새로운 ORM [Dapper]를 사용하고 있습니다 : 매개 변수화 된 SQL을 비즈니스 객체에 매핑 우리는 완전한 ORM으로 사용하지 않고 관계 나 다른 종소리 나 호루라기를하지 않습니다. 이것은 성능이 중요하지 않은 LINQ-2-SQL을 계속 사용하고 매퍼를 사용하기 위해 모든 인라인 SQL을 포팅합니다. 더 빠르고 유연하기 때문입니다. "

5
@Slauma는 몇 달 전의 진술입니다. 일반적으로 SO에 대한 모든 새 작업은 Dapper에서 수행됩니다. 예를 들어 오늘 추가 한 새 테이블은 dbml 파일에도 없습니다.
Sam Saffron

1
@ Sam : SO의 현재 데이터 액세스 전략에 대한 새로운 블로그 게시물이 있습니까? 겠습니까 매우 흥미로운! 그 동안 Dapper가 확장 되었습니까? Dapper는 완전한 ORM이 아니며 관계를 지원하지 않으며 업데이트, 삽입, 삭제, 트랜잭션, 변경 추적 등은
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.