Советы по ускорению записи JDBC?
Я пишу программу, которая много пишет в базу данных Postgres. В типичном сценарии я бы написал 100 000 строк в таблицу, которая хорошо нормализована (три внешних целочисленных ключа, комбинация которых является первичным ключом и индексом таблицы). Я использую PreparedStatements и executeBatch(), но мне может удастся нажать около 100 тыс. Строк примерно за 70 секунд на моем ноутбуке, когда встроенная база данных, которую мы заменяем (которая имеет те же ограничения и индексы внешнего ключа), делает это в 10.
Я новичок в JDBC, и я не ожидаю, что он побьет пользовательскую встроенную БД, но я надеялся, что это будет всего на 2-3 раза медленнее, а не 7x. Что-нибудь очевидное, что я, возможно, не хватает? выполняет ли порядок написания вопроса? (т.е. если это не порядок индекса?). Что посмотреть, чтобы выжать немного больше скорости?
Ответы
Ответ 1
Это проблема, с которой мне приходилось часто заниматься моим текущим проектом. Для нашего применения скорость вставки является критическим узким местом. Однако мы обнаружили для подавляющего большинства пользователей базы данных скорость выбора в качестве своего главного узкого места, чтобы вы обнаружили, что есть больше ресурсов, связанных с этой проблемой.
Итак, вот несколько решений, которые мы придумали:
Во-первых, все решения включают использование команды postgres COPY. Использование COPY для импорта данных в postgres на сегодняшний день является самым быстрым методом. Однако драйвер JDBC по умолчанию в настоящее время не поддерживает COPY через сетевой сокет. Итак, если вы хотите использовать его, вам нужно будет сделать одно из двух способов:
- Драйвер JDBC исправлен для поддержки COPY, например .
- Если данные, которые вы вставляете, и база данных находятся на одном физическом компьютере, вы можете записать данные в файл в файловой системе, а затем использовать команду COPY для импорта данных навалом.
Другие опции для увеличения скорости используют JNI, чтобы попасть в apg postgres, чтобы вы могли разговаривать через unix-сокет, удаляя индексы и pg_bulkload, Однако, в конце, если вы не реализуете COPY, вы всегда найдете неудобную производительность.
Ответ 2
Проверьте, установлено ли для вашего подключения значение autoCommit. Если autoCommit имеет значение true, тогда, если у вас есть 100 элементов в пакете при вызове executeBatch, он выдаст 100 отдельных коммитов. Это может быть намного медленнее, чем вызов executeBatch(), за которым следует одно явное commit().
Я бы избегал соблазна отказаться от индексов или внешних ключей во время вставки. Это ставит таблицу в состояние непригодности, пока ваша загрузка запущена, поскольку никто не может запросить таблицу, пока индексы не исчезли. Кроме того, кажется, что это достаточно безопасно, но что вы делаете, когда пытаетесь снова включить ограничение, и он терпит неудачу, потому что произошло то, чего вы не ожидали? RDBMS имеет ограничения целостности по какой-либо причине, и их отключение даже "на некоторое время" является опасным.
Ответ 3
Очевидно, вы можете попытаться изменить размер своей партии, чтобы найти оптимальный размер для вашей конфигурации, но я сомневаюсь, что вы получите коэффициент 3.
Вы также можете попытаться настроить структуру базы данных. У вас могут быть лучшие характеристики при использовании одного поля в качестве первичного ключа, чем использование сконфигурированного ПК. В зависимости от уровня целостности, который вам нужен, вы можете сэкономить довольно много времени, дезактивируя проверки целостности вашей БД.
Вы также можете изменить используемую вами базу данных. Предполагается, что MySQL очень хорош для высокоскоростных простых вставок... и я знаю, что есть вилка MySQL вокруг, которая пытается сократить функциональные возможности, чтобы получать очень высокие показатели при высокоскоростном доступе.
Удачи!
Ответ 4
попробуйте отключить индексы и повторно подключить их после вставки. также, оберните весь процесс в транзакции