2011-03-31 2 views
1

우리는 일대일 대응 문제, NHProf 선택 N + 1을 직면하고 있습니다. 경고, FetchMode.Join을 사용하기위한 기준 변경 중 N + 1 문제가 해결되지 않았습니다. 다음은 세부 사항입니다.일대일 연결 문제, NHProf 선택 N + 1 경고 표시, FetchMode.Join을 사용하지 않는 기준 변경 N + 1 문제 해결 안 함?

소프트웨어 버전 정보 : NH 버전 : 1.2 .NET 버전 : 3.5 DB : 오라클 11g 2 수준 캐시 : 사용

HBM 파일 및 클래스 개체.

설명 '샘플'엔티티는 0 또는 1 개의 '연관' 엔티티를 포함 할 수 있습니다. 'Association'엔티티에는 'Sample'엔티티의 외래 키 제약 조건이 있습니다.

Sample.hbm.xml

<?xml version="1.0" encoding="utf-8" ?> 
<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2" 
assembly="NHSample" namespace="NHSample"> 
<class name="Sample" table="SAMPLE" proxy="Sample" 
polymorphism="explicit" > 
     <id name="Id" type="Decimal" unsaved-value="-1"> 
         <column name="SA_ID" sql-type="NUMBER" not-null="true" 
unique="true"/> 
         <generator class="sequence"> 
           <param name="sequence">SA_ID_SEQ</param> 
         </generator> 
    </id> 
     <property name="SampleName" type="String"> 
       <column name="SAMPLE_NAME" length="100" sql-type="VARCHAR2" not- 
null="false"/> 
     </property> 
     <one-to-one name="Association" class="Association" property- 
ref="SampleAssociated" cascade="all-delete-orphan"/> 
    </class> 
</hibernate-mapping> 

Sample.cs

namespace NHSample 
{ 
    public class Sample 
    { 
     public virtual decimal Id 
     { 
      get ; 
      set ; 
     } 

     public virtual string SampleName 
     { 
      get ; 
      set ; 
     } 

     public virtual Association Association 
     { 
      get ; 
      set ; 
     } 
    } 
} 

Association.hbm.xml

<?xml version="1.0" encoding="utf-8" ?> 
<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2" 
assembly="NHSample" namespace="NHSample"> 
    <class name="Association" table="ASSOCIATION"> 
    <id name="Id" type="Decimal" unsaved-value="-1"> 
     <column name="AS_ID" sql-type="NUMBER" not-null="true" 
unique="true"/> 
     <generator class="sequence"> 
     <param name="sequence">AS_ID_SEQ</param> 
     </generator> 
    </id> 
     <property name="AssociationName" type="String"> 
       <column name="ASSOCIATION_NAME" length="100" sql-type="VARCHAR2" not- 
null="false"/> 
     </property> 
    <many-to-one name="SampleAssociated" class="Sample"> 
     <column name="SA_ID" sql-type="NUMBER" not-null="true"/> 
    </many-to-one> 
    </class> 
</hibernate-mapping> 

Association.cs

namespace NHSample 
{ 
    public class Association 
    { 
     public virtual decimal Id 
     { 
      get ; 
      set ; 
     } 

     public virtual string AssociationName 
     { 
      get ; 
      set ; 
     } 

     public virtual Sample SampleAssociated 
     { 
      get ; 
      set ; 
     } 
    } 
} 
WITHOUT의 fetchMode 7백45경1천5백15조5백36억9천1백36만3천2백10

기준 = 샘플 엔티티에 액세스하기 위해 사용 조인 Criteria.List()를 실행 한 경우

class Program 
    { 
     static void Main(string[] args) 
     { 
      using (ISession session = SessionFactory.OpenSession()) 
      { 
       var electedIds = new List<decimal>() { 1, 2, 3 }; 

       ICriteria criteria = 
session.CreateCriteria(typeof(Sample)); 
       criteria.Add(Expression.In("Id", electedIds)); 

       var list = criteria.List(); 
      } 
      Console.ReadKey(); 
     } 
    } 

는 NHProf는 N + 1 개 경보를 보였다. 다음은 NHProf에서 보여준 SQL 구문입니다.

- 문 # 1

SELECT this_.SA_ID     as SA1_0_1_, 
     this_.SAMPLE_NAME    as SAMPLE2_0_1_, 
     associatio2_.AS_ID   as AS1_1_0_, 
     associatio2_.ASSOCIATION_NAME as ASSOCIAT2_1_0_, 
     associatio2_.SA_ID   as SA3_1_0_ 
FROM SAMPLE this_ 
     left outer join ASSOCIATION associatio2_ 
     on this_.SA_ID = associatio2_.SA_ID 
WHERE this_.SA_ID in (1 /* :p0 */,2 /* :p1 */,3 /* :p2 */) 

- 문 # 2

SELECT associatio0_.AS_ID   as AS1_1_0_, 
     associatio0_.ASSOCIATION_NAME as ASSOCIAT2_1_0_, 
     associatio0_.SA_ID   as SA3_1_0_ 
FROM ASSOCIATION associatio0_ 
WHERE associatio0_.SA_ID = 1 /* :p0 */ 

- 문 # 3

SELECT associatio0_.AS_ID   as AS1_1_0_, 
     associatio0_.ASSOCIATION_NAME as ASSOCIAT2_1_0_, 
     associatio0_.SA_ID   as SA3_1_0_ 
FROM ASSOCIATION associatio0_ 
WHERE associatio0_.SA_ID = 2 /* :p0 */ 

- 문 # 4

SELECT associatio0_.AS_ID   as AS1_1_0_, 
     associatio0_.ASSOCIATION_NAME as ASSOCIAT2_1_0_, 
     associatio0_.SA_ID   as SA3_1_0_ 
FROM ASSOCIATION associatio0_ 
WHERE associatio0_.SA_ID = 3 /* :p0 */ 
FETCHMODE.Join를 사용 cirteria 수정

사용 NHProf 웹 사이트 제안 : 여전히 N + 1 경고를 표시하고 다음

class Program 
    { 
     static void Main(string[] args) 
     { 
      using (ISession session = SessionFactory.OpenSession()) 
      { 
       var electedIds = new List<decimal>() { 1, 2, 3 }; 

       ICriteria criteria = 
session.CreateCriteria(typeof(Sample)); 
       criteria.SetFetchMode("Association", FetchMode.Join); 
       criteria.Add(Expression.In("Id", electedIds)); 

       var listByIds = criteria.List(); 
      } 
      Console.ReadKey(); 
     } 
    } 

NHProf는 SQL 쿼리입니다.

- 문 # 1

SELECT this_.SA_ID     as SA1_0_1_, 
     this_.SAMPLE_NAME    as SAMPLE2_0_1_, 
     associatio2_.AS_ID   as AS1_1_0_, 
     associatio2_.ASSOCIATION_NAME as ASSOCIAT2_1_0_, 
     associatio2_.SA_ID   as SA3_1_0_ 
FROM SAMPLE this_ 
     left outer join ASSOCIATION associatio2_ 
     on this_.SA_ID = associatio2_.SA_ID 
WHERE this_.SA_ID in (1 /* :p0 */,2 /* :p1 */,3 /* :p2 */) 

- 문 # 2

SELECT associatio0_.AS_ID   as AS1_1_0_, 
     associatio0_.ASSOCIATION_NAME as ASSOCIAT2_1_0_, 
     associatio0_.SA_ID   as SA3_1_0_ 
FROM ASSOCIATION associatio0_ 
WHERE associatio0_.SA_ID = 1 /* :p0 */ 

- 문 # 3

SELECT associatio0_.AS_ID   as AS1_1_0_, 
     associatio0_.ASSOCIATION_NAME as ASSOCIAT2_1_0_, 
     associatio0_.SA_ID   as SA3_1_0_ 
FROM ASSOCIATION associatio0_ 
WHERE associatio0_.SA_ID = 2 /* :p0 */ 

- 문 # 4

SELECT associatio0_.AS_ID   as AS1_1_0_, 
     associatio0_.ASSOCIATION_NAME as ASSOCIAT2_1_0_, 
     associatio0_.SA_ID   as SA3_1_0_ 
FROM ASSOCIATION associatio0_ 
WHERE associatio0_.SA_ID = 3 /* :p0 */ 

이 시나리오에서이 추가 SQL 구문과 N + 1 문제를 해결하는 방법에 대한 의견.

감사합니다.

답변

3

이것은 NHibernate의 알려진 이슈입니다; Join 페칭은 다양한 상황에서 N + 1 문제를 방지하지 못합니다. 조인 페칭을 사용하는 첫 번째 쿼리에는 실제로 조인 및 매핑 된 필드가 포함됩니다. NHibernate는 매핑에 따라 적절한 쿼리를 구성하고 있지만 결합 된 자식 컬렉션에 해당 정보를 전달하지 않으므로 다시 돌아가서 N 개의 쿼리를 실행하여 자식을 가져옵니다.

여기에서 JIRA 항목을 볼 수 있습니다 : https://nhibernate.jira.com/browse/NH-2534. Hibernate 팀은 장비에 박차를 가하고 벌레의 백로에 전진하고있다. 나는 이걸 강조하고 싶다. (나는 그렇게 부를 것이고, 내 의견에 의해 입증 된대로 자신의 N + 1 문제를 해결하기 위해 새로운 빌드를 기다리고있다. 이 정확한 버그에), 그래서 나는 그들이 그것에 도착하자마자 고쳐질 것이라고 생각할 것이다.

개인적으로, NHibernate가 외래 키 쿼리를 사용하여 lazy-load 매핑에 기본적으로 알려질 수있는 2- 패스 쿼리 솔루션은 개인적으로 신경 쓰지 않습니다. 현재, 직접 IQuery를 구성하여 자식을로드하여이 동작을 지정할 수 있습니다. NH에 의해 생성 된 Lazy 프록시는 외래 키 쿼리를 사용하여 검색된 ID로 사전 초기화되지만 그 후에는 전체 데이터를 ID별로 한 번에 하나씩 가져옵니다. 그건 미친 짓이야. 당신이 NH를 사용하지 않는다면 그렇게하지 못할 것입니다.

+1

현재 JIRA 링크 : https://nhibernate.jira.com/browse/NH-2534 –