Рекомендации по производительности базы данных при пакетном импорте больших наборов данных - PullRequest
0 голосов
/ 23 декабря 2008

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

Например, допустим, мы отслеживаем людей. В базе данных есть таблицы с именами Person и Address. Существуют соответствующие сущности JPA и классы DAO.

Поверх уровня JPA находится сервисный уровень, отвечающий за различные операции. Одной из операций является импорт потенциально большого набора данных из внешнего устаревшего источника (например, людей из телефонной книги). Для каждого человека он должен проверить, существует ли он уже в базе данных. Затем он должен создать или обновить человека по мере необходимости. У каждого человека есть адрес, поэтому необходимо также создать соответствующую перекрестную ссылку и создать адрес.

Моя проблема в том, что эта операция может быть медленной для больших наборов данных. Мой текущий алгоритм:

for (Person person: allPersons)
{
    check if person exists in database
    check if address exists in database
    create or update person and address as necessary
}

Что бы вы посоветовали для улучшения производительности?

С макушки головы я могу подумать:

  1. Изменение логики импорта для извлечения и сохранения данных в базе данных с использованием запросов. Например, вместо того, чтобы проверять, существует ли человек в цикле for, отправьте все ключи человека в базу данных одним запросом. Каждый обработанный человек обрабатывается в памяти.
  2. Добавьте мое собственное кэширование в классы DAO.
  3. Используйте внешнее решение для кэширования (например, memcached).

Я всегда могу пойти с # 1 путем реструктуризации, чтобы минимизировать запросы. Недостатком является то, что мой уровень обслуживания теперь очень хорошо знает уровень DAO. Его реализация теперь продиктована нижним уровнем базы данных. Есть и другие проблемы, такие как использование слишком большого количества памяти. Этот захват из базы данных, затем процесс в памяти кажется очень доморощенным и идет вразрез с готовыми решениями, такими как JPA. Мне любопытно, что другие будут делать в этом случае.

Редактировать: Кэширование не поможет, так как каждый человек, которого запрашивают в цикле, отличается.

Ответы [ 2 ]

1 голос
/ 23 декабря 2008

Есть два решения, которые я нашел, которые работают. Одним из них является обработка фрагмента за раз. После закрытия каждого чанка происходит перезапуск сеанса. Я пытался использовать методы flush clear в сеансе, но иногда он просто функционировал так, как вы ожидаете. Кажется, что запуск и остановка транзакции между партиями работают лучше всего.

Если производительность является серьезной проблемой, просто сломайтесь и сделайте это в JDBC. Hibernate добавляет слишком много накладных расходов для пакетной обработки больших наборов данных, где важны память и производительность.

0 голосов
/ 01 января 2009

Ваш подход приведет к слишком большому количеству отдельных запросов к базе данных; выглядит как 4n + 1. Если возможно, я бы написал запрос (возможно, в необработанном SQL), который проверяет наличие адреса person + все за один раз.

Возможно, вы захотите работать с StatelessSession вместо стандартного Hibernate Session. Поскольку он не имеет кеша 1-го уровня, он должен поддерживать ваши требования к памяти ниже.

http://www.hibernate.org/hib_docs/reference/en/html/batch-statelesssession.html

Если это не сработает для вас, вам нужно взглянуть на параметры пакета в Hibernate:

http://www.hibernate.org/hib_docs/reference/en/html/batch.html

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