MySQLには「apps」と「icons」の2つのテーブルがあり、それぞれ約75万行あります。Hibernateでは、次のようにモデル化していました。
public class App {
@Basic
private String title;
@OneToOne(mappedBy = "app")
private Icon icon;
// etc...
}
public class Icon {
@Basic
private String name;
@OneToOne
private App app;
// etc...
}
この関係を追加すると、すぐにパフォーマンスの問題が発生しました。1つのアプリでの読み取りに1秒以上かかりました。Hibernateが生成しているSQLを調べたところ、次のように結合していることがわかりました。
select
apps.id as app_id,
apps.title as app_title,
icons.id as icon_id,
icons.name as icon_name
from
apps
left outer join
icons
on apps.id=icons.app_id
where
apps.id="zyz";
注釈に追加@Fetch(FetchMode.SELECT)
するとパフォーマンスが大幅に向上し、実質的に同じ結果が得られるように約30ミリ秒に短縮されることがわかりました。@Fetch(FetchMode.SELECT)
注釈付きで生成されたSQLは次のとおりです。
select
apps.id as app_id,
apps.title as title
from
apps
where
apps.id="xyz";
select
icons.id as icon_id,
icons.name as icon_name
from
icons
where
icons.app_id="xyz";
左外側の結合が非常に遅いのはなぜですか?結合されたクエリの「説明」は次のように表示されます。
+----+-------------+-------+-------+---------------+---------+---------+-------+--------+-------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+-------+-------+---------------+---------+---------+-------+--------+-------+
| 1 | SIMPLE | apps | const | PRIMARY | PRIMARY | 767 | const | 1 | |
| 1 | SIMPLE | icons | ALL | NULL | NULL | NULL | NULL | 783556 | |
+----+-------------+-------+-------+---------------+---------+---------+-------+--------+-------+
したがって、複数選択クエリの場合は1行であるのに対し、明らかにすべての行にアクセスしています。結合は、icons.app_idにあるインデックスを使用できませんか?
PS:はい、タイミングの実行の合間に「RESETQUERYCACHE」を使用しました。
更新:主キーに移動し、bigint
それを使用して、の代わりにテーブルを結合しました。結合のVARCHAR
パフォーマンスは、「複数選択」方式と同等になりました。