У меня есть две таблицы в MySQL, «приложения» и «значки», каждая из которых содержит около 750 тыс. Строк. В Hibernate я моделировал им нравится:MySQL и 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 секунду. Я исследовал 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)
к аннотациям значительно ускорило работу, доведя его до около 30ms для эффективного и тому же результата. Вот полученный SQL с @Fetch(FetchMode.SELECT)
аннотацию:
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 | |
+----+-------------+-------+-------+---------------+---------+---------+-------+--------+-------+
Так это, по-видимому посещения каждой строки, против одной строки для множественного выбора запроса. Не может ли соединение использовать индекс, который у меня есть на icons.app_id?
PS: Да, я использовал «RESET QUERY CACHE» между сеансами синхронизации.
Update: переехал на первичный ключ bigint
, использовал это, чтобы присоединиться к таблицам в вместо VARCHAR
и производительности объединения в настоящее время на одном уровне с методом «несколько выбирает».
Действительно, это MyISAM, автогенерированный из устаревшего приложения Hibernate. На самом деле уже есть индекс на icons.app_id. Я заинтересован в переходе на InnoDB, особенно если производительность, скорее всего, улучшится, но я прочитал обратное (возможно, дезинформировал?) Ключами являются VARCHAR (255) (опять же, бит Hibernate autogenerated mess). Изменил бы PK на более традиционный целочисленный тип, а не на нашу эффективность бизнес-ключа? Большое спасибо за ваше время, спасибо. –
Я всегда обнаружил, что с использованием типов int datatypes работают лучше, чем не-int, когда дело доходит до индексирования. Одна вещь, которую вы можете сделать, это создать int PK в новой таблице, но при этом сохранить старый ключ varchar для устаревших ссылок. Затем при обновлении приложения попробуйте вместо этого использовать новый столбец PK. Можете ли вы опубликовать схемы таблиц? Возможно, вы сможете предложить более глубокое понимание. –
Уверен: http://pastebin.com/BUKWszxP –