использование В спящем режиме к загрузке 20K продукты, изменение объекта и обновление к дб

Я использую, в спящем режиме для обновления 20K продуктов в моей базе данных.

На данный момент я вытягиваю в 20K продуктах, цикличном выполнении через них и изменяю некоторые свойства и затем обновляю базу данных.

так:

load products

foreach products
   session begintransaction
   productDao.MakePersistant(p);
   session commit();

На данный момент вещи являются довольно медленными по сравнению с Вашим стандартом jdbc, что я могу сделать для ускорения вещей?

Я уверен, что делаю что-то не так здесь.

7
задан Pascal Thivent 2 May 2010 в 17:05
поделиться

4 ответа

Правильное место в документации для такого рода обработки - вся Глава 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).

10
ответ дан 6 December 2019 в 12:48
поделиться

Если это псевдокод, я бы порекомендовал вывести транзакцию за пределы цикла или, по крайней мере, создать двойной цикл, если все 20K продуктов в одной транзакции слишком много:

load products
foreach (batch)
{
   try
   {
      session beginTransaction()
      foreach (product in batch)
      {
          product.saveOrUpdate()
      }
      session commit()
   }
   catch (Exception e)
   {
       e.printStackTrace()
       session.rollback()
   }
}

Также я бы рекомендовал что вы пакетируете свои ОБНОВЛЕНИЯ вместо того, чтобы отправлять каждое по отдельности в базу данных. В этом случае слишком большой сетевой трафик. Объедините каждый кусок в единый пакет и отправьте их все сразу.

5
ответ дан 6 December 2019 в 12:48
поделиться

Самый быстрый способ выполнить пакетное обновление - это преобразовать его в один оператор 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

0
ответ дан 6 December 2019 в 12:48
поделиться

Я согласен с приведенным выше ответом о просмотре главы о пакетной обработке.

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

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

1
ответ дан 6 December 2019 в 12:48
поделиться
Другие вопросы по тегам:

Похожие вопросы: