#java #hibernate #jdbc #etl
#java #переход в спящий режим #jdbc #etl
Вопрос:
У меня есть эта новая задача — загрузить ~ 100 миллионов строк из базы данных Oracle и вставить их на удаленный сервер базы данных MySQL.
Я разделил проблему на две части:
- серверный сервер REST, отвечающий за загрузку данных на сервер MySQL;
- Java-приложение на стороне клиента, которое отвечает за загрузку источника данных Oracle.
На стороне Java я использовал обычный JDBC для загрузки содержимого с разбиением на страницы и передачи его по проводам на сервер. Этот подход работает хорошо, но он делает код громоздким и не очень масштабируемым, поскольку я сам разбиваю страницы на страницы, используя Oracle ROWNUM…..ГДЕ ROWNUM> x и ROWNUM < y.
Теперь я попробовал Hibernate StatelessSession с моими объектами, отображаемыми через аннотации. Код намного более удобочитаемый и чистый, но производительность хуже.
Я слышал об инструментах ETL и SpringBatch, но я не очень хорошо их знаю. Существуют ли другие подходы к этой проблеме?
Заранее спасибо.
Обновить
Спасибо за бесценные предложения. Я выбрал использование SpringBatch для загрузки данных из базы данных Oracle, потому что среда довольно плотная, и у меня нет доступа к набору инструментов Oracle. SpringBatch — это trie и true. Для этапа записи данных я выбрал запись фрагментов записей с использованием файла ЗАГРУЗКИ ДАННЫХ MySQL, как вы все заявили. Службы REST находятся посередине, поскольку они скрыты друг от друга по соображениям безопасности.
Комментарии:
1. Просто используйте пакет spring. Не изобретайте что-то для решения задачи. Если у вас есть какие-либо поля SQL Server, лежащие вокруг, SSIS также отлично справится с этой задачей для вас.
Ответ №1:
100 миллионов строк — это довольно много. Вы можете спроектировать его множеством способов: REST-серверы, чтение JDBC, пакет Spring, интеграция Spring, спящий режим, ETL. Но суть в следующем: время.
Независимо от того, какую архитектуру вы выберете, вам в конечном итоге придется выполнять эти INSERT
s в MySQL. Ваш пробег может варьироваться, но просто для того, чтобы дать вам порядок величины: при 2 тыс. вставок в секунду потребуется полдня, чтобы заполнить MySQL 100 МЛН строк (источник).
Согласно тому же источнику LOAD DATA INFILE
, может обрабатывать около 25 тыс. вставок в секунду (примерно в 10 раз больше и около часа работы).
При этом с таким объемом данных я бы предложил:
-
дамп таблицы Oracle с использованием собственных инструментов базы данных Oracle, которые создают читаемый человеком контент (или читаемый компьютером, но вы должны иметь возможность его анализировать)
-
проанализируйте файл дампа, используя как можно более быстрые инструменты. Может
grep
быть, /sed
/gawk
/cut
будет достаточно? -
создайте целевой файл, совместимый с MySQL
LOAD DATA INFILE
(он очень настраиваемый) -
Импортируйте файл в MySQL, используя вышеупомянутую команду
Конечно, вы можете сделать это на Java с помощью приятного и читаемого кода, модульного тестирования и версионности. Но с таким объемом данных вам нужно быть прагматичным.
Это для начальной загрузки. После этого, вероятно, Spring Batch будет хорошим выбором. Если вы можете, попробуйте подключить свое приложение напрямую к обеим базам данных — опять же, это будет быстрее. С другой стороны, это может быть невозможно по соображениям безопасности.
Если вы хотите быть очень гибким и не привязывать себя к базам данных напрямую, предоставьте как ввод (Oracle), так и вывод (MySQL) за веб-сервисами (REST тоже подойдет). Интеграция с Spring вам очень поможет.
Комментарии:
1. В качестве альтернативы, используйте JDBC для извлечения записей из Oracle и записи их в формате «LOAD DATA INFILE» в файл или последовательность файлов. Вероятно, немного медленнее, чем при использовании встроенного инструментария oracle, но вы пропускаете шаг и по-прежнему используете скорость загрузки файла данных, что, вероятно, является более трудоемким фактором.
Ответ №2:
Вы можете использовать Scriptella для передачи данных между базами данных. Вот пример файла преобразования XML:
<!DOCTYPE etl SYSTEM "http://scriptella.javaforge.com/dtd/etl.dtd">
<etl>
<connection id="in" url="jdbc:oracle:thin:@localhost:1521:ORCL"
classpath="ojdbc14.jar" user="scott" password="tiger"/>
<connection id="out" url="jdbc:mysql://localhost:3306/fromdb"
classpath="mysql-connector.jar" user="user" password="password"/>
<!-- Copy all table rows from one to another database -->
<query connection-id="in">
SELECT * FROM Src_Table
<!-- For each row executes insert -->
<script connection-id="out">
INSERT INTO Dest_Table(ID, Name) VALUES (?id,?name)
</script>
</query>
</etl>