0

非効率な Hibernate クエリが発生しています。その原因は、他の場所で読んだいわゆる N+1 問題であると考えています。ただし、オブジェクトがネストされているため、問題を解決する方法がわかりません。また、オンラインで見たほとんどの解決策の例は些細なことです。

これが私のアプリケーションの簡単な説明です。

ExecutionTraceクラスと1対多の関係にあるクラスがありTraceLineます。TraceLine次に、クラスと 1 対多の関係を持ちTraceReferenceます。これらの各クラスには、Hibernate によって生成された id 属性があります。(すべてのクラスにはいくつかのメンバー変数が含まれていますが、ここでは省略します。)

私のアプリケーションでは、特定の を照会しています。その後、アプリケーションはそのすべてのオブジェクトとそのオブジェクトExecutionTraceを反復処理します。したがって、これらすべての関係に を設定しました。TraceLineTraceReferenceLazyCollectionOptionfalse

// ExecutionTrace.java:
...
@Id @GeneratedValue
@Column(name = "file_id")
public long id;
...
@OneToMany(mappedBy = "container_trace_", cascade = CascadeType.ALL)
@LazyCollection(LazyCollectionOption.FALSE)
@OrderBy(clause = "id")
public List<TraceLine> lines_ = new ArrayList<TraceLine>();
...


// TraceLine.java:
...
@Id @GeneratedValue
@Column(name = "trace_line_id")
@Index(name = "traceIDIndex")
public long id;
...
@ManyToOne(cascade = CascadeType.ALL)
@JoinColumn(name = "file_id")
@LazyCollection(LazyCollectionOption.TRUE)
public ExecutionTrace container_trace_;
...
@OneToMany(mappedBy = "trace_line_", cascade = CascadeType.ALL)
@LazyCollection(LazyCollectionOption.FALSE)
@OrderBy(clause = "id")
public List<TraceReference> trace_references_ = new ArrayList<TraceReference>();
...


// TraceReference.java:
...
@Id @GeneratedValue
@Column(name = "trace_reference_id")
@Index(name="TraceReferenceIDIndex")
public long id;
...
@ManyToOne(cascade = CascadeType.ALL)
@JoinColumn(name = "trace_line_id")
@LazyCollection(LazyCollectionOption.TRUE)
public TraceLine trace_line_;
...

を選択するための私の休止状態のクエリExecutionTraceは次のとおりです。

String f_hash = ...;

Transaction tx3 = session.beginTransaction();
    String queryString = " from ExecutionTrace where hash_ = '"+ f_hash +"'";

List<ExecutionTrace> res2 = session.createQuery(queryString).list();
tx3.commit();

私の単純なテスト ケースの 1 つで、1 つのオブジェクトがありExecutionTrace、そこには 645TraceLine個のオブジェクトが含まれており、それぞれに 1 ~ 5個のTraceReferenceオブジェクトが含まれています。クエリと、それらすべてを反復するコードは、適度なハードウェアで 50 秒以上かかります。データベースの PostgreSQL は、アプリケーションと同じマシンで実行されています。

Hibernate によってスローされた SQL クエリを見て、次のことに気付きました。

  • TraceLineすべてのオブジェクトを選択するクエリが 1 つあります。これはいい。
  • オブジェクトを選択するための 645 のクエリがありTraceReferenceます。これは悪いです。さらに、それらはすべて多くの外部結合が行われているため、非効率的です。

たとえば、TraceReference へのクエリは次のとおりです。

    select
        trace_refe0_.trace_line_id as trace5_6_18_,
        trace_refe0_.trace_reference_id as trace1_18_,
        trace_refe0_.trace_reference_id as trace1_7_17_,
        trace_refe0_.new_value as new2_7_17_,
        trace_refe0_.old_value as old3_7_17_,
        trace_refe0_.operand_id as operand4_7_17_,
        trace_refe0_.trace_line_id as trace5_7_17_,
        operand1_.operand_id as operand1_11_0_,
        operand1_.operand_index as operand2_11_0_,
        operand1_.is_dest as is3_11_0_,
        operand1_.is_source as is4_11_0_,
        operand1_.operand_size as operand5_11_0_,
        operand1_.operand_u_prop_id as operand6_11_0_,
        operand1_.maps_to_variable as maps7_11_0_,
        operandtyp2_.operand_prop_id as operand2_12_1_,
        operandtyp2_1_.constant_value as constant1_13_1_,
        operandtyp2_2_.register_name as register1_14_1_,
        operandtyp2_4_.base_operand_id as base2_16_1_,
        operandtyp2_4_.displacement_operand_id as displace3_16_1_,
        operandtyp2_4_.index_operand_id as index4_16_1_,
        operandtyp2_4_.ml_name as ml1_16_1_,
        operandtyp2_4_.scale_operand_id as scale5_16_1_,
        operandtyp2_.DTYPE as DTYPE12_1_,
        register3_.operand_prop_id as operand2_12_2_,
        register3_1_.register_name as register1_14_2_,
        constant4_.operand_prop_id as operand2_12_3_,
        constant4_1_.constant_value as constant1_13_3_,
        register5_.operand_prop_id as operand2_12_4_,
        register5_1_.register_name as register1_14_4_,
        constant6_.operand_prop_id as operand2_12_5_,
        constant6_1_.constant_value as constant1_13_5_,
        variable7_.variable_id as variable1_18_6_,
        variable7_.file_id as file6_18_6_,
        variable7_.function_id as function7_18_6_,
        variable7_.variable_is_argument as variable2_18_6_,
        variable7_.variable_is_global as variable3_18_6_,
        variable7_.variable_is_static as variable4_18_6_,
        variable7_.variable_name as variable5_18_6_,
        variable7_.data_type_id as data8_18_6_,
        sourcefile8_.file_id as file2_0_7_,
        sourcefile8_.file_path as file3_0_7_,
        sourcefile8_.file_name as file4_0_7_,
        sourcefile8_.source_lang as source5_0_7_,
        function9_.function_id as function1_8_8_,
        function9_.file_id as file6_8_8_,
        function9_.function_end_address as function2_8_8_,
        function9_.function_address as function3_8_8_,
        function9_.function_name as function4_8_8_,
        function9_.function_is_static as function5_8_8_,
        sourcefile10_.file_id as file2_0_9_,
        sourcefile10_.file_path as file3_0_9_,
        sourcefile10_.file_name as file4_0_9_,
        sourcefile10_.source_lang as source5_0_9_,
        datatype11_.data_type_id as data2_19_10_,
        datatype11_.defined_by as defined5_19_10_,
        datatype11_.data_type_length as data3_19_10_,
        datatype11_.data_type_name as data4_19_10_,
        datatype11_2_.pointer_to as pointer1_20_10_,
        datatype11_3_.array_size as array1_21_10_,
        datatype11_3_.contains_type as contains2_21_10_,
        datatype11_4_.enumerator_count as enumerator1_22_10_,
        datatype11_5_.type_ as type1_24_10_,
        datatype11_6_.constant_of_type as constant1_25_10_,
        datatype11_7_.return_type as return1_27_10_,
        datatype11_.DTYPE as DTYPE19_10_,
        sourcefile12_.file_id as file2_0_11_,
        sourcefile12_.file_path as file3_0_11_,
        sourcefile12_.file_name as file4_0_11_,
        sourcefile12_.source_lang as source5_0_11_,
        datatype13_.data_type_id as data2_19_12_,
        datatype13_.defined_by as defined5_19_12_,
        datatype13_.data_type_length as data3_19_12_,
        datatype13_.data_type_name as data4_19_12_,
        datatype13_2_.pointer_to as pointer1_20_12_,
        datatype13_3_.array_size as array1_21_12_,
        datatype13_3_.contains_type as contains2_21_12_,
        datatype13_4_.enumerator_count as enumerator1_22_12_,
        datatype13_5_.type_ as type1_24_12_,
        datatype13_6_.constant_of_type as constant1_25_12_,
        datatype13_7_.return_type as return1_27_12_,
        datatype13_.DTYPE as DTYPE19_12_,
        datatype14_.data_type_id as data2_19_13_,
        datatype14_.defined_by as defined5_19_13_,
        datatype14_.data_type_length as data3_19_13_,
        datatype14_.data_type_name as data4_19_13_,
        datatype14_2_.pointer_to as pointer1_20_13_,
        datatype14_3_.array_size as array1_21_13_,
        datatype14_3_.contains_type as contains2_21_13_,
        datatype14_4_.enumerator_count as enumerator1_22_13_,
        datatype14_5_.type_ as type1_24_13_,
        datatype14_6_.constant_of_type as constant1_25_13_,
        datatype14_7_.return_type as return1_27_13_,
        datatype14_.DTYPE as DTYPE19_13_,
        datatype15_.data_type_id as data2_19_14_,
        datatype15_.defined_by as defined5_19_14_,
        datatype15_.data_type_length as data3_19_14_,
        datatype15_.data_type_name as data4_19_14_,
        datatype15_2_.pointer_to as pointer1_20_14_,
        datatype15_3_.array_size as array1_21_14_,
        datatype15_3_.contains_type as contains2_21_14_,
        datatype15_4_.enumerator_count as enumerator1_22_14_,
        datatype15_5_.type_ as type1_24_14_,
        datatype15_6_.constant_of_type as constant1_25_14_,
        datatype15_7_.return_type as return1_27_14_,
        datatype15_.DTYPE as DTYPE19_14_,
        datatype16_.data_type_id as data2_19_15_,
        datatype16_.defined_by as defined5_19_15_,
        datatype16_.data_type_length as data3_19_15_,
        datatype16_.data_type_name as data4_19_15_,
        datatype16_2_.pointer_to as pointer1_20_15_,
        datatype16_3_.array_size as array1_21_15_,
        datatype16_3_.contains_type as contains2_21_15_,
        datatype16_4_.enumerator_count as enumerator1_22_15_,
        datatype16_5_.type_ as type1_24_15_,
        datatype16_6_.constant_of_type as constant1_25_15_,
        datatype16_7_.return_type as return1_27_15_,
        datatype16_.DTYPE as DTYPE19_15_,
        datatype17_.data_type_id as data2_19_16_,
        datatype17_.defined_by as defined5_19_16_,
        datatype17_.data_type_length as data3_19_16_,
        datatype17_.data_type_name as data4_19_16_,
        datatype17_2_.pointer_to as pointer1_20_16_,
        datatype17_3_.array_size as array1_21_16_,
        datatype17_3_.contains_type as contains2_21_16_,
        datatype17_4_.enumerator_count as enumerator1_22_16_,
        datatype17_5_.type_ as type1_24_16_,
        datatype17_6_.constant_of_type as constant1_25_16_,
        datatype17_7_.return_type as return1_27_16_,
        datatype17_.DTYPE as DTYPE19_16_ 
    from
        TraceReference trace_refe0_ 
    left outer join
        Operand operand1_ 
            on trace_refe0_.operand_id=operand1_.operand_id 
    left outer join
        OperandProperties operandtyp2_ 
            on operand1_.operand_u_prop_id=operandtyp2_.operand_prop_id 
    left outer join
        Constant operandtyp2_1_ 
            on operandtyp2_.operand_prop_id=operandtyp2_1_.operand_prop_id 
    left outer join
        Register operandtyp2_2_ 
            on operandtyp2_.operand_prop_id=operandtyp2_2_.operand_prop_id 
    left outer join
        UnknownOperandProperties operandtyp2_3_ 
            on operandtyp2_.operand_prop_id=operandtyp2_3_.operand_prop_id 
    left outer join
        MemoryLocation operandtyp2_4_ 
            on operandtyp2_.operand_prop_id=operandtyp2_4_.operand_prop_id 
    left outer join
        OperandProperties register3_ 
            on operandtyp2_4_.base_operand_id=register3_.operand_prop_id 
    left outer join
        Register register3_1_ 
            on register3_.operand_prop_id=register3_1_.operand_prop_id 
    left outer join
        OperandProperties constant4_ 
            on operandtyp2_4_.displacement_operand_id=constant4_.operand_prop_id 
    left outer join
        Constant constant4_1_ 
            on constant4_.operand_prop_id=constant4_1_.operand_prop_id 
    left outer join
        OperandProperties register5_ 
            on operandtyp2_4_.index_operand_id=register5_.operand_prop_id 
    left outer join
        Register register5_1_ 
            on register5_.operand_prop_id=register5_1_.operand_prop_id 
    left outer join
        OperandProperties constant6_ 
            on operandtyp2_4_.scale_operand_id=constant6_.operand_prop_id 
    left outer join
        Constant constant6_1_ 
            on constant6_.operand_prop_id=constant6_1_.operand_prop_id 
    left outer join
        Variable variable7_ 
            on operand1_.maps_to_variable=variable7_.variable_id 
    left outer join
        FileOnDisk sourcefile8_ 
            on variable7_.file_id=sourcefile8_.file_id 
    left outer join
        ObjectFile sourcefile8_1_ 
            on sourcefile8_.file_id=sourcefile8_1_.file_id 
    left outer join
        SourceFile sourcefile8_2_ 
            on sourcefile8_.file_id=sourcefile8_2_.file_id 
    left outer join
        SourceFunction function9_ 
            on variable7_.function_id=function9_.function_id 
    left outer join
        FileOnDisk sourcefile10_ 
            on function9_.file_id=sourcefile10_.file_id 
    left outer join
        ObjectFile sourcefile10_1_ 
            on sourcefile10_.file_id=sourcefile10_1_.file_id 
    left outer join
        SourceFile sourcefile10_2_ 
            on sourcefile10_.file_id=sourcefile10_2_.file_id 
    left outer join
        DataType datatype11_ 
            on variable7_.data_type_id=datatype11_.data_type_id 
    left outer join
        Pointer datatype11_1_ 
            on datatype11_.data_type_id=datatype11_1_.data_type_id 
    left outer join
        Pointer datatype11_2_ 
            on datatype11_.data_type_id=datatype11_2_.data_type_id 
    left outer join
        SourceArray datatype11_3_ 
            on datatype11_.data_type_id=datatype11_3_.data_type_id 
    left outer join
        Enum datatype11_4_ 
            on datatype11_.data_type_id=datatype11_4_.data_type_id 
    left outer join
        Typedef datatype11_5_ 
            on datatype11_.data_type_id=datatype11_5_.data_type_id 
    left outer join
        ConstantType datatype11_6_ 
            on datatype11_.data_type_id=datatype11_6_.data_type_id 
    left outer join
        FunctionType datatype11_7_ 
            on datatype11_.data_type_id=datatype11_7_.data_type_id 
    left outer join
        FileOnDisk sourcefile12_ 
            on datatype11_.defined_by=sourcefile12_.file_id 
    left outer join
        ObjectFile sourcefile12_1_ 
            on sourcefile12_.file_id=sourcefile12_1_.file_id 
    left outer join
        SourceFile sourcefile12_2_ 
            on sourcefile12_.file_id=sourcefile12_2_.file_id 
    left outer join
        DataType datatype13_ 
            on datatype11_2_.pointer_to=datatype13_.data_type_id 
    left outer join
        Pointer datatype13_1_ 
            on datatype13_.data_type_id=datatype13_1_.data_type_id 
    left outer join
        Pointer datatype13_2_ 
            on datatype13_.data_type_id=datatype13_2_.data_type_id 
    left outer join
        SourceArray datatype13_3_ 
            on datatype13_.data_type_id=datatype13_3_.data_type_id 
    left outer join
        Enum datatype13_4_ 
            on datatype13_.data_type_id=datatype13_4_.data_type_id 
    left outer join
        Typedef datatype13_5_ 
            on datatype13_.data_type_id=datatype13_5_.data_type_id 
    left outer join
        ConstantType datatype13_6_ 
            on datatype13_.data_type_id=datatype13_6_.data_type_id 
    left outer join
        FunctionType datatype13_7_ 
            on datatype13_.data_type_id=datatype13_7_.data_type_id 
    left outer join
        DataType datatype14_ 
            on datatype13_3_.contains_type=datatype14_.data_type_id 
    left outer join
        Pointer datatype14_1_ 
            on datatype14_.data_type_id=datatype14_1_.data_type_id 
    left outer join
        Pointer datatype14_2_ 
            on datatype14_.data_type_id=datatype14_2_.data_type_id 
    left outer join
        SourceArray datatype14_3_ 
            on datatype14_.data_type_id=datatype14_3_.data_type_id 
    left outer join
        Enum datatype14_4_ 
            on datatype14_.data_type_id=datatype14_4_.data_type_id 
    left outer join
        Typedef datatype14_5_ 
            on datatype14_.data_type_id=datatype14_5_.data_type_id 
    left outer join
        ConstantType datatype14_6_ 
            on datatype14_.data_type_id=datatype14_6_.data_type_id 
    left outer join
        FunctionType datatype14_7_ 
            on datatype14_.data_type_id=datatype14_7_.data_type_id 
    left outer join
        DataType datatype15_ 
            on datatype14_5_.type_=datatype15_.data_type_id 
    left outer join
        Pointer datatype15_1_ 
            on datatype15_.data_type_id=datatype15_1_.data_type_id 
    left outer join
        Pointer datatype15_2_ 
            on datatype15_.data_type_id=datatype15_2_.data_type_id 
    left outer join
        SourceArray datatype15_3_ 
            on datatype15_.data_type_id=datatype15_3_.data_type_id 
    left outer join
        Enum datatype15_4_ 
            on datatype15_.data_type_id=datatype15_4_.data_type_id 
    left outer join
        Typedef datatype15_5_ 
            on datatype15_.data_type_id=datatype15_5_.data_type_id 
    left outer join
        ConstantType datatype15_6_ 
            on datatype15_.data_type_id=datatype15_6_.data_type_id 
    left outer join
        FunctionType datatype15_7_ 
            on datatype15_.data_type_id=datatype15_7_.data_type_id 
    left outer join
        DataType datatype16_ 
            on datatype15_6_.constant_of_type=datatype16_.data_type_id 
    left outer join
        Pointer datatype16_1_ 
            on datatype16_.data_type_id=datatype16_1_.data_type_id 
    left outer join
        Pointer datatype16_2_ 
            on datatype16_.data_type_id=datatype16_2_.data_type_id 
    left outer join
        SourceArray datatype16_3_ 
            on datatype16_.data_type_id=datatype16_3_.data_type_id 
    left outer join
        Enum datatype16_4_ 
            on datatype16_.data_type_id=datatype16_4_.data_type_id 
    left outer join
        Typedef datatype16_5_ 
            on datatype16_.data_type_id=datatype16_5_.data_type_id 
    left outer join
        ConstantType datatype16_6_ 
            on datatype16_.data_type_id=datatype16_6_.data_type_id 
    left outer join
        FunctionType datatype16_7_ 
            on datatype16_.data_type_id=datatype16_7_.data_type_id 
    left outer join
        DataType datatype17_ 
            on datatype16_7_.return_type=datatype17_.data_type_id 
    left outer join
        Pointer datatype17_1_ 
            on datatype17_.data_type_id=datatype17_1_.data_type_id 
    left outer join
        Pointer datatype17_2_ 
            on datatype17_.data_type_id=datatype17_2_.data_type_id 
    left outer join
        SourceArray datatype17_3_ 
            on datatype17_.data_type_id=datatype17_3_.data_type_id 
    left outer join
        Enum datatype17_4_ 
            on datatype17_.data_type_id=datatype17_4_.data_type_id 
    left outer join
        Typedef datatype17_5_ 
            on datatype17_.data_type_id=datatype17_5_.data_type_id 
    left outer join
        ConstantType datatype17_6_ 
            on datatype17_.data_type_id=datatype17_6_.data_type_id 
    left outer join
        FunctionType datatype17_7_ 
            on datatype17_.data_type_id=datatype17_7_.data_type_id 
    where
        trace_refe0_.trace_line_id=? 
    order by
        trace_refe0_.trace_reference_id
TRACE [main] 06/26/13 10:00:54 preparing statement
TRACE [main] 06/26/13 10:00:54 binding parameter [1] as [BIGINT] - 82883

内部結合を実行するようにクエリを変更してみました。

    String queryString =    " from ExecutionTrace as et " +
               "inner join fetch et.lines_ as lines " +
        "where et.hash_ = '"+ f_hash +"'";

これにより、 を選択するためのクエリは 0 になり、 を選択するためTraceLineのクエリは 645 回になりましTraceReferenceた。助け無し。次に、複数の内部結合を試しました。

    String queryString = 
    " from ExecutionTrace as et " +
       "inner join fetch et.lines_ as lines " +
       "inner join fetch lines.trace_references_ " +
    "where et.hash_ = '"+ f_hash +"'";

これにより、例外が発生しました。

Exception in thread "main" org.hibernate.loader.MultipleBagFetchException: cannot simultaneously fetch multiple bags.

問題の解決に近づいていると感じていますが、簡単なものが欠けているだけです。

4

1 に答える 1