2016-06-21 2 views
11

Я работаю над системой, которая загружает данные из облачной системы в локальную базу данных (PostgreSQL, MySQL, ...). Теперь у меня проблема с производительностью PostgreSQL, потому что для ввода данных требуется много времени.Медленная вставка на PostgreSQL с использованием JDBC

Число столбцов и размер данных могут отличаться. В примере проекта у меня есть таблица с ок. 170 столбцов. Существует один уникальный индекс - но даже после падения индекса скорость вставки не изменилась.

Я использую драйвер JDBC для подключения к базе данных, и я вставляю данные партиями по 250 строк (используя NamedParameterJdbcTemplate).

Мне потребовалось ок. 18 секунд для ввода данных на Postgres. Тот же набор данных на MySQL занял у меня всего лишь. Это огромная разница - откуда она взялась? Является ли драйвер Postgres JDBC медленным? Может ли он быть настроен каким-то образом, чтобы сделать его быстрее? Я что-то пропустил? Разница между Postgres и MySQL настолько велика. Любые другие идеи, как сделать это быстрее?

Я сделал образец проекта, который доступен на Github - https://github.com/varad/postgresql-vs-mysql. Все происходит в LetsGo class методом «run».

+1

Вы могли бы включить больше отладки, чтобы увидеть, что на самом деле медленное? (вставка, фиксация, подключение)? для отладки в java (для драйвера) loglevel = 2 (https://jdbc.postgresql.org/documentation/80/connect.html) для регистрации на стороне сервера https://www.drupal.org/node/560192 –

+0

В каких версиях мы говорим? Вы пытались совершить транзакцию? – m0skit0

+0

Кроме того, вы пытались перевернуть и вставить его сначала в MySQL, и посмотреть, что происходит (например, 'letsGo.run (Type.MYSQL); letGo.run (Type.POSTGRES);')? Также как вы проверяете время? – m0skit0

ответ

5

Кажется, что это сочетание Spring «ошибка» и водитель «ошибка» ,

Весна пытается определить тип данных столбца каждый раз, когда вызывается setValue(). Он делает это, вызывая PreparedStatementMetaData.getParameterMetaData()

Это, видимо, вызывает «подготовить» заявление будет отправлено в базу данных, которая сама по себе является довольно быстро (никогда не более 1мс на моем ноутбуке), но, как он вызывается для каждого столбца для каждая строка суммируется до большого количества времени (она вызывается для каждого значения, не равного нулю, что приводит к примерно 23 000 вызовов)

В некоторой степени это скорее ошибка Spring, а ошибка драйвера, поскольку не кэширование параметра мета данные на самом деле не имеют смысла (по крайней мере, на мой взгляд). Драйвер JDBC MySQL не поддерживает getParameterMetaData(), и Spring знает об этом, и поэтому эта «ошибка» не отображается с MySQL, потому что Spring никогда не вызывает этот метод.

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

Spring можно убедить не получить утверждение мета-данные через свойство spring.jdbc.getParameterType.ignore

Итак, положив:

System.setProperty("spring.jdbc.getParameterType.ignore", "true"); 

перед тем строку:

LetsGo letsGo = new LetsGo(); 

это поведение является отключен.

Имущество должно быть установлено до Весна инициализирована.

Когда я делаю это с вашим образцом проекта, вставка работает в 500 мс на моем ноутбуке.


Редактировать

После просмотра комментария относительно использования драйвера Postgres-NG я копал в источники «официального» водитель и водитель NG, а драйвер NG кэширует метаданные параметров после первого вызова, тогда как официальный драйвер не объясняет, почему использование драйвера NG намного быстрее (без отключения вызова весной)

+0

Спасибо! Я считаю, что это прекрасный ответ. Хотя, если я устанавливаю свойство, я получаю «DataIntegrityViolationException», не знаю, почему. Вам нужно было изменить что-то еще, кроме добавления свойства? – varad

+0

@varad: нет, это единственное, что я изменил. –

+0

Интересно, я получаю «22P02: недопустимый синтаксис ввода для целого числа». Но я думаю, это еще одна проблема. – varad

1

попробуйте использовать драйвер pgjdbc-ng, а затем сравните ваши результаты.

Он доступен здесь: http://impossibl.github.io/pgjdbc-ng/

+1

Ничего себе, с этим драйвером это было очень быстро. Всего полсекунды! – varad

0

В строке подключения, добавьте следующее:

&useServerPrepStmts=false&rewriteBatchedStatements=true 
+0

Спасибо, но это не имело никакого значения. – varad

-1

Надеюсь, вы используете пул соединений DB. Вы можете попробовать C3P0. Spring (JDBCTemplate) не обеспечивает реализацию пула соединений.

Смежные вопросы