Подтвердить что ты не робот

Hibernate производит различный SQL для каждого запроса

Я только что протестировал свое приложение под профилировщиком и выяснил, что в строках sql используется около 30% моей памяти! Это странно.

В памяти приложения хранится много таких строк. Это SQL-запросы, сгенерированные спящим режимом, обратите внимание на разные числа и завершающие символы подчеркивания:

select avatardata0_.Id as Id4305_0_,...... where avatardata0_.Id=? for update
select avatardata0_.Id as Id4347_0_,...... where avatardata0_.Id=? for update

Вот часть, которую я не могу понять. Почему спящий режим должен генерировать разные строки sql с разными идентификаторами типа " Id4305_0 _" для каждого запроса? Почему он не может использовать одну строку запроса для всех одинаковых запросов? Это какой-то трюк, чтобы обойти кеширование запросов?

Я был бы очень признателен, если бы кто-нибудь описал меня, почему это происходит, и как избежать такого истощения ресурсов.

UPDATE

Ok. Я нашел это. Я ошибался, предполагая утечку памяти. Это была моя ошибка. Hibernate работает по назначению.

Мое приложение создало 121 (!) SessionFactories в 10 потоках, они выпустили около 2300 экземпляров SingleTableEntityPersisters. И каждый SingleTableEntityPersister генерирует около 15 SQL-запросов с разными идентификаторами. Hibernate был вынужден генерировать около 345 000 различных SQL-запросов. Все в порядке, ничего странного:)

4b9b3361

Ответ 1

Существует логика строки запроса, генерируемой спящим режимом. Его основная цель - получить уникальные псевдонимы для имен таблиц и столбцов.

Из вашего запроса

select avatardata0_.Id as Id4305_0_,...... where avatardata0_.Id=?

avatardata0_ == > avatardata является псевдонимом таблицы, а 0_ добавляется, чтобы указать, что это первая таблица в запросе. Итак, если бы это была вторая таблица (или Entity) в запросе, она должна была отображаться как avatardata1_. Он использует ту же логику для псевдонимов столбцов.

Итак, таким образом избегаются все возможные конфликты.

Вы видите эти запросы, потому что вы включаете флаг show_sql в настройке. Предназначен для отладки запросов. После того, как приложение начнет работать, вы должны отключить его.

Подробнее о документах API здесь.

Я не очень хорошо знаю часть потребления памяти, но вы повторяете свои тесты с выключенным флагом и видите, есть ли какие-либо улучшения.

Ответ 2

Предполагая, что вы используете сервер sql, вы можете проверить объявление типа параметра для "?", убедившись, что объявление приводит к тому же объявлению с фиксированной длиной каждый раз.

Параметры динамической длины приведут к отдельным планам выполнения для каждого запроса. Это может привести к большому количеству ресурсов. То, что мы видим как ту же процедуру, интерпретируется сервером sql как другой запрос, предоставляя отдельный план выполнения.

Таким образом,

exec myprocedure @p1 varchar(3)='foo' 

и

exec myprocedure @p1 varchar(6)='foobar' 

приведет к разным планам. Просто из-за того, что объявления @p1 отличаются по размеру.

Об этом можно многое узнать. Если вышеизложенное относится к вам, я бы рекомендовал вам прочитать "snuffing параметра".

Ответ 3

Нет... вы можете создать общий запрос внутри спящего режима. Логика заключается в сопоставлении с таблицей и извлечении записи. Он используется для общего запроса для всей базы данных. Создайте общий запрос:

Пример:

select t.Id as Id4305_0_,...... from t where t.Id=?