Я работаю над задержкой чувствительная часть приложения, в основном я получу сетевое событие, преобразовывают данные и затем вставляют все данные в DB. После профилирования я вижу, что в основном все мое время проведено, пытаясь сохранить данные. вот код
private void insertAllData(Collection<Data> dataItems)
{
long start_time = System.currentTimeMillis();
long save_time = 0;
long commit_time = 0;
Transaction tx = null;
try
{
Session s = HibernateSessionFactory.getSession();
s.setCacheMode(CacheMode.IGNORE);
s.setFlushMode(FlushMode.NEVER);
tx = s.beginTransaction();
for(Data data : dataItems)
{
s.saveOrUpdate(data);
}
save_time = System.currentTimeMillis();
tx.commit();
s.flush();
s.clear();
}
catch(HibernateException ex)
{
if(tx != null)
tx.rollback();
}
commit_time = System.currentTimeMillis();
System.out.println("Save: " + (save_time - start_time));
System.out.println("Commit: " + (commit_time - save_time));
System.out.println();
}
Размер набора всегда - меньше чем 20. вот данные синхронизации, которые я вижу:
Save: 27
Commit: 9
Save: 27
Commit: 9
Save: 26
Commit: 9
Save: 36
Commit: 9
Save: 44
Commit: 0
Это сбивает с толку меня. Я полагаю что save
должно быть быстрым и все время должен быть потрачен на commit
. но ясно я неправ. Я также попытался удалить транзакцию (не действительно необходимый), но я видел худшие времена... Я установил, в спящем режиме jdbc.batch_size=20...
Я могу ожидать получать целых 500 сообщений/секунда, таким образом, мне будет нужна единственная обработка сообщений для нахожений под 20 миллисекундами.
мне нужна эта операция, чтобы быть максимально быстро, идеально только было бы одно распространение в прямом и обратном направлениях к базе данных. Как я могу сделать это?
Отодвиньте генерацию первичного ключа от автоматического увеличения на стороне сервера. Ваш Java-код должен отвечать за генерацию PK, чтобы избежать обходов.
Для приличной производительности массовой вставки вам нужен метод, которому не нужно обращаться к базе данных при каждом вызове saveOrUpdate. Использование UUID в качестве первичного ключа или реализация HiLo может помочь в достижении этого. В противном случае массовая вставка не происходит.
Оптимизаторы объединенные или объединенные-ло являются лучшим выбором для обеспечения производительности и взаимодействия с другими внешними системами.
Честно говоря, я не знайте, что можно сделать разумный вывод из вашего теста и из «мер», которые вы показываете (я подозреваю, что много накладных расходов из-за разминки, коллекция очень мала, а выборка очень мала).
В любом случае, я могу сказать вам, что ваш текущий код не будет масштабироваться, и вы, скорее всего, взорвете Сессию при передаче более крупной коллекции. Вам необходимо очищать сеанс через равные промежутки времени (каждые 20 записей, если размер пакета равен 20).
На самом деле, я рекомендую прочитать целиком главу 13. Пакетная обработка .
Некоторые базовые вещи:
Пакетная обработка является частью JDBC 2.0, она позволяет вам выполнять несколько операторов в "пакете"; идея состоит в том, чтобы уменьшить задержку при обходе (вы можете выполнять несколько пакетов за транзакцию).
Statement stmt = dbCon.createStatement("insert into DataTable values (?,?,?)");
stmt.setInt(1, x1); stmt.setInt(2, x2), stmt.setString(3, "some value");
stmt.addBatch();
...
stmt.setInt(1, x2); stmt.setInt(2, x3), stmt.setString(3, "some other value");
stmt.addBatch();
stmt.executeBatch();
dbCon.commit();
Возможно, вы можете использовать это в качестве эталонного теста. Я бы также посмотрел на SQL, который генерирует hibernate, чтобы увидеть, выполняет ли он запрос на вставку для получения сгенерированных идентификаторов.