mybatis springboot копирование данных с одного сервера базы данных на другой

Вопрос или проблема

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

@Bean(value = "batchSqlSession")
@Autowired
public SqlSessionTemplate batchSqlSession(SqlSessionFactory sqlSessionFactory) {       
    return new SqlSessionTemplate(sqlSessionFactory, ExecutorType.BATCH);
}

Класс Репозитория

@Repository
@Slf4j
public class EmployeeDAO {
    private final SqlSessionTemplate sqlSessionTemplate;
    private final EmployeeMapper employeeSessionMapper;
    public EmployeeDAO (EmployeeMapper employeeSessionMapper,
                          @Qualifier("batchSqlSession") SqlSessionTemplate sqlSessionTemplate) {
        this.sqlSessionTemplate = sqlSessionTemplate;
        this.employeeSessionMapper = sqlSessionTemplate.getMapper(EmployeeMapper.class);
    }

    public List<EmployeeEnt> getEmployeeEnt() {
        return this.employeeSessionMapper.getEmployeeEnt();
    }

    @Transactional
    public void insertEmployeeEnt(List<EmployeeEnt> employeeEntList) {
        employeeEntList.stream().parallel().forEach(employeeEnt-> {
            try{
                employeeSessionMapper.insertEmployeeEnt(employeeEnt);
            } catch(Exception ex){
                log.error("Исключение - {} при вставке данных {}",ex.getMessage(),employeeEnt.toString());
            }
        });
        sqlSessionTemplate.flushStatements();
        sqlSessionTemplate.clearCache();
    }

    public void truncateEmployeeEnt() {
        this.employeeSessionMapper.truncateEmployeeEnt();
        sqlSessionTemplate.flushStatements();
        sqlSessionTemplate.clearCache();
    }
}

Из класса сервиса

new EmployeeDAO().truncateEmployeeEnt();
new EmployeeDAO().insertEmployeeEnt(employeeDAO.getEmployeeEnt());

Mapper

<insert id="employeeEnt" parameterType="EmployeeEnt">        
            Вставить в EMPLOYEE_DET(..) значения {#{empId},#{empName},...
</insert>

Метод getEmployeeEnt() из исходного сервера базы данных возвращает 1 миллион записей, и я очищаю целевую базу данных перед вставкой 1 миллиона записей. Вставка занимает более 2 часов и никогда не завершается. Но если я выполняю это при копировании данных между 2 схемами одной и той же базы данных, это занимает менее 10 минут, но если это 2 разных сервера Oracle, она никогда не завершается.

Делаю ли я что-то неправильно, чтобы исправить и ускорить вставки?
Я не могу создавать ссылки на базы данных, потому что источник – производственные данные, и создание ссылок не разрешено.
Экспорт данных в формате CSV, а затем использование sqlldr в Java для загрузки – это вариант?

Ответ или решение

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

1. Разделение процесса копирования

Одним из наиболее эффективных способов повышения скорости вставки данных является оптимизация процесса обработки и уменьшение нагрузки на базу данных. Вместо фиксации каждого отдельного вставляемого элемента можно разбивать данные на меньшие партии.

Пример последовательной обработки:

@Transactional
public void insertEmployeeEnt(List<EmployeeEnt> employeeEntList) {
    int batchSize = 1000; // Оптимальный размер пакета может варьироваться
    List<EmployeeEnt> batchList = new ArrayList<>();

    for (EmployeeEnt employee : employeeEntList) {
        batchList.add(employee);
        if (batchList.size() == batchSize) {
            employeeSessionMapper.insertEmployeeEntBatch(batchList);
            sqlSessionTemplate.flushStatements();
            sqlSessionTemplate.clearCache();
            batchList.clear();
        }
    }

    // Вставляем оставшиеся записи
    if (!batchList.isEmpty()) {
        employeeSessionMapper.insertEmployeeEntBatch(batchList);
        sqlSessionTemplate.flushStatements();
        sqlSessionTemplate.clearCache();
    }
}

2. Использование механизмов параллелизма

stream().parallel() был использован для параллелизации, однако это может привести к увеличенной конкуренции за ресурсы и блокировкам. Примените разделение одной операции на несколько потоков, но с осторожностью. Используйте Executors с фиксированным количеством потоков, чтобы контролировать потребление ресурсов.

3. Параметризованный запрос

Использование одного SQL-запроса для вставки множества записей может значительно увеличить скорость выполнения. Вам может понадобиться изменить ваш mapper для поддержки пакетной вставки:

<insert id="insertEmployeeEntBatch" parameterType="List">
    INSERT ALL
    <foreach collection="list" item="employee" separator="">
        INTO EMPLOYEE_DET (empId, empName, ...)
        VALUES (#{employee.empId}, #{employee.empName}, ...)
    </foreach>
    SELECT * FROM dual;
</insert>

4. Использование SQL*Loader

Если ни один из вышеуказанных методов не дает значительного улучшения, рассмотрите возможность использования SQLLoader. Это стандартный инструмент Oracle для загрузки объемных данных, и его сочетание с CSV может значительно ускорить процесс. Вы можете экспортировать ваши данные в формате CSV и затем загрузить их с помощью SQLLoader в фоновом режиме, что также снижает нагрузку на текущие ресурсы БД.

5. Тестирование и оптимизация

Рекомендуется провести тестирование с различными размерами пакетов и мониторинг метрик производительности БД: загрузка CPU, время выполнения запросов, использование диска и сетевых ресурсов.

Заключение

Копирование большого объема данных между различными серверами БД – это задачи, требующие осторожного подхода и оптимизации. Применение предлагаемых стратегий, таких как пакетная вставка, параллельная обработка в контролируемых рамках и использование инструментов, таких как SQL*Loader, поможет значительно улучшить производительность и скорость ваших операций. Не забудьте протестировать каждый вариант и оценить его производительность в соответствии с вашими требованиями.

Оцените материал
Добавить комментарий

Капча загружается...