Массовое обновление базы данных / вставка из файла CSV

8

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

У меня есть файл CSV, содержащий, скажем, 10000 строк. Эти строки необходимо вставить / обновить в базе данных.

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

Одним из возможных решений является то, что я могу читать по одной строке, проверять записи в базе данных и строить запросы на вставку / обновление соответственно. Но этот процесс может занять много времени для создания запросов на обновление / вставку и выполнения их в базе данных. Иногда мой CSV-файл может содержать миллионы записей.

Есть ли другой быстрый способ добиться этой функции?


источник
Попробуйте обработать его по частям, иначе большое чтение CSV за один выстрел приведет к OutOfMemory!
@TheNewIdiot, что не произойдет, если использовать достаточно памяти, как приличный сервер, который направляет как минимум 2 ГБ оперативной памяти в JVM. Это также будет зависеть от типа данных в CSV-файле и от того, будет ли процесс выполняться в одном процессе или рядом с другим, обрабатываемым на сервере.
@Luiggi Mendoza: Я согласен с вами. У нас достаточно памяти для обработки большого файла CSV в производстве.

Ответы:

7

В Oracle есть хорошая технология, которая называется External Tables. В вашем сценарии вы можете получить доступ к своим внешним текстовым данным с помощью внешних таблиц из базы данных и обновить существующие данные в базе данных с помощью операторов SQL, которые вам нравятся и используются, например, INSERTи MERGEт. Д.

В большинстве случаев использование утилит, предоставляемых Oracle, является лучшим способом выполнения ETL. И поскольку ваш вопрос звучит скорее как административный, я предлагаю вам взглянуть на мой предыдущий пост на DBA Stack Exchange «Обновление базы данных Oracle из CSV» .

ОБНОВЛЕНИЕ: Этот подход работает очень хорошо для чтения внешних данных в базе данных. Как правило, вы определяете внешний формат данных каждый раз, когда вам нужно обработать простой текстовый файл, который имеет новый формат. После создания внешней таблицы вы можете запросить ее, как настоящую таблицу базы данных. Всякий раз, когда есть новые данные для импорта, вы просто заменяете базовый файл (ы) на лету без необходимости воссоздания внешней таблицы. Поскольку внешняя таблица может запрашиваться как любая другая таблица базы данных, вы можете написать операторы SQL для заполнения других таблиц базы данных.

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

Ясир Арсанукаев
источник
Я согласен, что это одно из решений для достижения моей цели. Как этот подход может быть пригоден для динамической обработки CSV? Значит, пользователь моего приложения имеет возможность загружать несколько файлов в разных форматах (в этом случае внешние истории должны создаваться на лету). Кроме того, один файл CSV может содержать данные, которые необходимо заполнить в несколько таблиц.
1

Я думаю, что вы должны использовать SQL * Loader для загрузки файла CSV во временную таблицу, а затем использовать оператор MERGE для вставки данных в рабочую таблицу.
SQL * Loader даст вам больше гибкости, чем внешние таблицы, и если вы используете прямую загрузку, это действительно быстро. И MERGE сделает именно то, что вам нужно - вставьте новые записи и обновите существующие.
Несколько ссылок для начала:
http://docs.oracle.com/cd/B19306_01/server.102/b14215/ldr_concepts.htm
http://docs.oracle.com/cd/B28359_01/server.111/b28286/statements_9016 .htm

Миндаугас Риауба
источник
1
Когда вы загружаете данные в базу данных с помощью SQL Loader, процесс DBWR или процесс SQL Loader записывают буферы в файлы данных. При последующем перемещении загруженных данных в другие таблицы база данных выполняет другой ввод-вывод. Я не думаю, что эта дополнительная работа может быть оправдана. Между прочим, когда Внешние таблицы используют драйвер ORACLE_LOADER, синтаксис для определения формата входных данных является тем же самым, который используется утилитой sqlldr, потому что по сути они представляют собой одну и ту же технологию и, таким образом, могут использоваться взаимозаменяемо. Внешние таблицы в этом сценарии предпочтительнее, так как нет необходимости сначала загружать данные в базу данных
Ясир Арсанукаев
Как обычно, ответ "это зависит" :). В нашем случае обычно удобнее сначала загрузить временную таблицу, а потом обработать. Поскольку прямая загрузка пути не генерирует повтор, то дополнительные операции ввода-вывода практически незаметны среди других операций. В других случаях, конечно, другие методы будут лучше.
Миндаугас Риауба
0

PreparedStatements сделает создание запросов на вставку или обновление очень быстрым. У вас должно быть три PreparedStatements: один для вставки, один для обновления и один для проверки, находится ли строка в таблице. Если вы можете сохранить идентификаторы между CSV-файлом и новой базой данных, то проверка наличия строки с использованием поля primaryID также должна быть очень быстрой.

Использование пакетной вставки может повысить производительность. Когда вы просматриваете файл CSV, вы затем проверяете, существует ли уже строка, а затем либо обновляете, либо добавляете строку в команду пакетной вставки. Вы должны проверить этот вопрос SO для сравнения скорости этих двух подходов.

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

  int nThreads = Runtime.getRuntime().availableProcessors();

Каждый поток получает свое собственное соединение с БД, и когда ваш код перебирает файл, строки CSV могут передаваться различным потокам. Это намного сложнее, поэтому я сделал бы это только в том случае, если бы меня заставили требования к производительности.

Сообщество
источник
Спасибо за ответ. Опять же, для этого потребуется анализ файла CSV и заполнение значений в подготовленные операторы. При использовании подхода «Внешние таблицы» я вижу, что разбор файлов можно переместить на сторону базы данных, где приложению не нужно заботиться об этом. Кроме того, я использую JPA с Hibernate в моем приложении. Я ищу вариант, который может быть комбинацией JPA / Hibernate / Oracle, который облегчает отсутствие разбора файлов, хорошую производительность, удобство обслуживания и гибкость.