非効率な Hibernate クエリが発生しています。その原因は、他の場所で読んだいわゆる N+1 問題であると考えています。ただし、オブジェクトがネストされているため、問題を解決する方法がわかりません。また、オンラインで見たほとんどの解決策の例は些細なことです。
これが私のアプリケーションの簡単な説明です。
ExecutionTrace
クラスと1対多の関係にあるクラスがありTraceLine
ます。TraceLine
次に、クラスと 1 対多の関係を持ちTraceReference
ます。これらの各クラスには、Hibernate によって生成された id 属性があります。(すべてのクラスにはいくつかのメンバー変数が含まれていますが、ここでは省略します。)
私のアプリケーションでは、特定の を照会しています。その後、アプリケーションはそのすべてのオブジェクトとそのオブジェクトExecutionTrace
を反復処理します。したがって、これらすべての関係に を設定しました。TraceLine
TraceReference
LazyCollectionOption
false
// 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.
問題の解決に近づいていると感じていますが、簡単なものが欠けているだけです。