Я использую, в спящем режиме для обновления 20K продуктов в моей базе данных.
На данный момент я вытягиваю в 20K продуктах, цикличном выполнении через них и изменяю некоторые свойства и затем обновляю базу данных.
так:
load products
foreach products
session begintransaction
productDao.MakePersistant(p);
session commit();
На данный момент вещи являются довольно медленными по сравнению с Вашим стандартом jdbc, что я могу сделать для ускорения вещей?
Я уверен, что делаю что-то не так здесь.
Правильное место в документации для такого рода обработки - вся Глава 13. Пакетная обработка.
Здесь есть несколько очевидных ошибок в вашем текущем подходе:
вы должны включить пакетную обработку JDBC и установить ее на разумное число (10-50):
hibernate.jdbc.batch_size 20
вы должны flush()
и затем clear()
сессию через регулярные промежутки времени (каждые n записей, где n равно параметру hibernate.jdbc.batch_size
), иначе она будет продолжать расти и может взорваться (с OutOfMemoryException
) в какой-то момент.
Ниже приведен пример, приведенный в разделе 13.2. Пакетные обновления, иллюстрирующий это:
Session session = sessionFactory.openSession();
Transaction tx = session.beginTransaction();
ScrollableResults customers = session.getNamedQuery("GetCustomers")
.setCacheMode(CacheMode.IGNORE)
.scroll(ScrollMode.FORWARD_ONLY);
int count=0;
while ( customers.next() ) {
Customer customer = (Customer) customers.get(0);
customer.updateStuff(...);
if ( ++count % 20 == 0 ) {
//flush a batch of updates and release memory:
session.flush();
session.clear();
}
}
tx.commit();
session.close();
Вы также можете рассмотреть возможность использования StatelessSession.
Другим вариантом может быть использование операций в стиле DML (на HQL!): UPDATE FROM? EntityName (WHERE where_conditions)?
. Вот пример HQL UPDATE:
Session session = sessionFactory.openSession();
Transaction tx = session.beginTransaction();
String hqlUpdate = "update Customer c set c.name = :newName where c.name = :oldName";
// or String hqlUpdate = "update Customer set name = :newName where name = :oldName";
int updatedEntities = s.createQuery( hqlUpdate )
.setString( "newName", newName )
.setString( "oldName", oldName )
.executeUpdate();
tx.commit();
session.close();
Опять же, за подробностями обратитесь к документации (особенно к тому, как работать со значениями свойств version
или timestamp
с помощью ключевого слова VERSIONED
).
Если это псевдокод, я бы порекомендовал вывести транзакцию за пределы цикла или, по крайней мере, создать двойной цикл, если все 20K продуктов в одной транзакции слишком много:
load products
foreach (batch)
{
try
{
session beginTransaction()
foreach (product in batch)
{
product.saveOrUpdate()
}
session commit()
}
catch (Exception e)
{
e.printStackTrace()
session.rollback()
}
}
Также я бы рекомендовал что вы пакетируете свои ОБНОВЛЕНИЯ вместо того, чтобы отправлять каждое по отдельности в базу данных. В этом случае слишком большой сетевой трафик. Объедините каждый кусок в единый пакет и отправьте их все сразу.
Самый быстрый способ выполнить пакетное обновление - это преобразовать его в один оператор SQL и выполнить в сеансе как необработанный sql. Что-то вроде
update TABLE set (x=y) where w=z;
В противном случае вы можете попытаться выполнить меньше транзакций и выполнять обновления пакетами:
start session
start transaction
products = session.getNamedQuery("GetProducs")
.setCacheMode(CacheMode.IGNORE)
.scroll(ScrollMode.FORWARD_ONLY);
count=0;
foreach product
update product
if ( ++count % 20 == 0 ) {
session.flush();
session.clear();
}
}
commit transaction
close session
Для получения дополнительной информации см. Документы сообщества Hibernate
Я согласен с приведенным выше ответом о просмотре главы о пакетной обработке.
Я также хотел добавить, что вы должны убедиться, что загружаете только то, что необходимо для изменений, которые вам необходимо внести в продукт.
Я имею в виду, что если продукт с нетерпением загружает большое количество других объектов, которые не важны для этой транзакции, вам следует подумать о том, чтобы не загружать соединенные объекты - это ускорит загрузку продуктов и в зависимости от их стратегии сохранения. , также может сэкономить ваше время при повторном сохранении продукта.