Как работает алгоритм пакетной выборки Hibernate?
Я нашел это описание алгоритма пакетной выборки в "Manning - Java Persistence with Hibernate":
Каков настоящий алгоритм пакетной выборки? (...) Представьте, что размер пакета равен 20, а общее количество 119 неинициализированных прокси должно быть загружено в пакетном режиме. Во время запуска Hibernate считывает метаданные сопоставления и создает 11 пакетных загрузчиков внутри. Каждый загрузчик знает, сколько прокси-серверов он может инициализировать: 20, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1. Цель состоит в том, чтобы минимизировать потребление памяти для создания загрузчика и создать достаточно загрузчиков, чтобы каждый возможна пакетная выборка. Другая цель, очевидно, минимизировать количество SQL-запросов. Для инициализации 119 прокси Hibernate выполняет семь пакетов (вы, вероятно, ожидали шесть, потому что 6 x 20 > 119). Применяемые пакетные загрузчики: пять раз по 20, один раз по 10 и один раз по 9, автоматически выбираемые Hibernate.
но я до сих пор не понимаю, как это работает.
- Почему 11 пакетных погрузчиков?
- Почему пакетные загрузчики могут инициализировать: 20, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1 прокси?
Если бы кто-нибудь мог представить пошаговый алгоритм...:)
2 ответа
Я не смог найти в Интернете никакой информации о том, как hibernate справляется с пакетной загрузкой, но, судя по вашей информации, можно предположить следующее:
Почему 11 пакетных погрузчиков?
При размере пакета 20, если вы хотите минимизировать количество загрузчиков, необходимое для любой комбинации прокси-серверов, в основном есть два варианта:
- создать загрузчик для 1,2,3,4,5,6,7,...20,21,22,23,... N неинициализированных прокси (глупо!) ИЛИ
- создать загрузчик для любого N между 1..9, а затем создать больше загрузчиков для
batch_size/2
(Рекурсивно)
Пример: для пакета размером 40 вы получите загрузчики для 40,20,10,9,8,7,6,5,4,3,2,1.
- Если у вас есть 33 неинициализированных прокси, вы можете использовать следующие загрузчики: 20, 10, 3
- Если у вас 119 неинициализированных прокси, вы можете использовать следующие загрузчики: 40 (x2), 20, 10, 9
- ...
Почему пакетные загрузчики могут инициализировать: 20, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1 прокси? Я думаю, что команда hibernate выбрала это как баланс между количеством загрузчиков, необходимых для загрузки "общего" числа N неинициализированных прокси, и потреблением памяти. Могли бы создать загрузчик для каждого N от 0 до batch_size
, но я подозреваю, что загрузчики занимают значительное место в памяти, так что это компромисс. Алгоритм может быть примерно таким (обоснованное предположение):
n = batch_size; while (n > 10)
1.1.
loader(n); n = n / 2
for n = 0..10 create loader(n)
Это помогает избежать создания большого количества различных подготовленных заявлений.
Каждый запрос (подготовленный оператор) должен быть проанализирован, а его план выполнения должен быть рассчитан и кэширован базой данных. Этот процесс может быть намного дороже, чем фактическое выполнение запроса, для которого оператор уже был кэширован.
Большое количество различных операторов может привести к удалению других кэшированных операторов из кэша, что приведет к снижению общей производительности приложения.
Кроме того, поскольку жесткий анализ, как правило, очень дорогой, он обычно быстрее выполняет несколько подготовленных кэшированных операторов (включая несколько обращений к базе данных), чем анализирует и выполняет новый. Таким образом, помимо очевидного преимущества сокращения количества различных операторов, на самом деле может быть быстрее получить все 119 объектов путем выполнения 11 кэшированных операторов, чем создавать и выполнять один новый, который содержит все 119 идентификаторов.
Как уже упоминалось в комментариях, Hibernate вызывает ArrayHelper.getBatchSizes
метод определения размеров партии для заданного максимального размера партии.