Problema em migração de base dados diferentes [Resolvido]

13 respostas
R

Olá pessoal…

Estou precisando fazer a migração de uma base de dados firebird para o mysql. A estrutura do banco é diferente, nome das tabelas e campos mudaram por isso não posso simplesmente exportar do firebird e importar do mysql direto. Tenho que fazer uma aplicação para tratar essas diferenças e inserir os dados vindos do firebird nas tabelas e campos correspondentes no mysql. Desenvolvi usando uma função que pega os dados no firebird e grava em um hashmap e outra função que pega esses dados do hashmap e grava no mysql, mas o desempenho ficou ruim e o consumo de memória ficou mto exagerado, inclusive com estouro dando o seguinte erro:

Limpei os hashmap após o uso, setei as sentenças sql como null para ver se melhorava, mas não resolveu.
Tentei fazer tb com uma única função que busca os dados, grava no resultset e insere no mysql desse mesmo resultset sem usar hashmap ou qualquer outra coisa, mas o problema continuou o mesmo, desempenho fraco e consumo exagerado de memória.

Para exemplicaficar, uma tabela de aproximadamente 40000 registros ta demorando entre 18 e 20 minutos para migrar os dados e ta estourando a memória, a aplicação chega a usar 1GB de memória.

Qual seria a melhor maneira de fazer um procedimento de migração de dados como esse? Alguém tem alguma idéia?

Desde já, agradeço a atenção de todos.

13 Respostas

B

eu usaria sql puro, aplicando os principios do KISS

R

Olá Balrog, obrigado pela resposta.

Bom, ja tentei fazer usando o sql puro mesmo. Apenas os dados que a consulta traz tem que ser guardado em algum lugar, e guarda no resultset aí a senteça de inserção pega do resultset e grava no mysql. Acho que essa é a maneira mais simples. Você teria alguma dica de como fazer diferente?

B

pra que vc escreve uma aplicacao para fazer isso?
faca um simples sql, que gere os scripts de insercao pra vc
i.e
select ‘insert into tab_dest values (’||coluna||’)’ from tab_source

J

Entendeu os principios do Kiss?

R

Olá balrog…

Bom, a aplicação é para tratar os problemas que falei. A base de dados mudou, a estrutura é diferente. É migração de firebird para mysql. Como fazer um sql direto, sem aplicação para pegar dados de um bd firebird e inserir no mysql? Esse sql seria executado onde? No firebird, no mysql?

L

Acredito que é possível tu fazer essa migração utilizando apenas SQL, senão me engano tens como conectar do mysql em outros bancos, não vou afirmar porque faz muito tempo que não trabalho com mysql.
Para a solução de desenvolver uma aplicação eu sugiro tu utilizar um framework de persistencia mapeando os dois bancos para fazer o “de para” ou caso continues utilizando jdbc sugiro que tu revise se estas sempre fechando as conexões e não faça o commit linha a linha.
Quanto a questão do teu out of memory, tu tens como aumentar o heap e ver se vai estourar…
Espero que tenha te ajudado…

V

Evite carregar os dados no hashmap.
Leia linha-a-linha e faça imediatamente a inserção no outro banco.

Crie estruturas intermediárias apenas para o que for estritamente necessário.

Se vc ler para o hashmap estará carregando a base toda para a memória, não é de surpreender que seu programa estoure.

E certifique-se de fechar corretamente Statements e ResultSets no processo.

R

Leoduval, vou ver essa possibilidade de conectar do mysql em outra base.

ViniGodoy, tentei fazer direto do ResultSet (busca no firebird, armazena nesse resultset, pega o valor nesse mesmo resultset e grava no mysql)

algo mais ou menos assim:

ResultSet rset = stmt.executeQuery("SELECT * FROM TURNO")//conecta no banco firebird e faz a busca

while (rset.next()) {

//pega os dados da busca no firebird e insere no novo banco
String sql_prov = "INSERT INTO VD_TURNO VALUES (" + "'" +
                        rset.getstring("CODTURNO") + "','" +
                        rset.getstring("ABERTURA") +"','" +
                        rset.getstring("FECHAMENTO") +"')";
                stmt = connNovoBanco.prepareStatement(sql_prov);
                stmt.execute(sql_prov);

}

Mas aí ocorre os problemas citados... alguma dica de como fazer diferente?

R

Pessoal, ainda tem mais uma coisa.

Alguns campos tem que ser tratado, pois na base antiga do firebird podiam ter valores nulos e na base nova não pode. Por isso tenho que fazer essa verificação.

V

Onde você está fechando seus statements?

R

Logo depois do while, quando ele não é mais utilizado. Segue o código da função que to usando para buscar no firebird e gravar no mysql:

public void buscarFirebird() {

        Statement stmt = null;
        int cont_aux = 1;

        try {

            stmt = connFirebird.createStatement();

            ResultSet rset = stmt.executeQuery("SELECT * FROM TURNO");

            while (rset.next()) {

           
        Calendar currenttime = Calendar.getInstance();
       
            try {

                

                //FUNÇÕES PARA VERIFICAR SE AS DATAS QUE VEM DO BANCO SÃO NULAS
                connNovoBanco.setAutoCommit(false);
                data_atual_abertura = rset.getTimestamp("DTABERTURA");
                if (rset.getTimestamp("DTABERTURA") == null) {
                    Timestamp data_aux = new Timestamp((currenttime.getTime()).getTime());
                    data_atual_abertura = data_aux;
                }
                if (rset.getTimestamp("DTABERTURA") != null) {
                    if (rset.getTimestamp("DTABERTURA").equals("")) {
                        Timestamp data_aux = new Timestamp((currenttime.getTime()).getTime());
                        data_atual_abertura = data_aux;
                    }
                }
                data_atual_fechamento = (Timestamp) rset.getTimestamp("DTFECHAMENTO");
                if (rset.getTimestamp("DTFECHAMENTO") == null) {
                    Timestamp data_aux = new Timestamp((currenttime.getTime()).getTime());
                    data_atual_fechamento = data_aux;
                }
                if (rset.getTimestamp("DTFECHAMENTO") != null) {
                    if (rset.getTimestamp("DTFECHAMENTO").equals("")) {
                        Timestamp data_aux = new Timestamp((currenttime.getTime()).getTime());
                        data_atual_fechamento = data_aux;
                    }
                }
                {
                    try {
                        if (rset.getString("CODPROD") != null) {
                            Statement stm = connNovoBanco.createStatement();
                            String sql_cep = "select * from CD_BICO where ID_BICO = '" + rset.getInt("CODPROD") + "'";
                            Statement stmtConsulta = connNovoBanco.createStatement(ResultSet.TYPE_SCROLL_INSENSITIVE, ResultSet.FETCH_FORWARD);
                            ResultSet rs = stm.executeQuery(sql_cep);
                            aux_codprod = (Integer)rset.getInt("CODPROD");
                            if (rs.next()) {
                                /** se encontrar algum resultado nesta busca entra no if */
                                /** dentro deste bloco vc seta o id do PRODUTO encontrado */
                                aux_codprod = rs.getInt("ID_BICO");
                            } else {
                                /** Se nao encontrar nenhum resultado na sua busca entra neste else */
                                /** seta o id do PRODUTO padrão dentro deste bloco */
                                aux_codprod = 999;
                                //hmTurno.put("CODPROD", 999);
                            }
                            stmtConsulta.close();
                            stm.close();
                            sql_cep = null;
                        }
                        if (rset.getString("CODLOJA") != null) {
                            Statement stm = connNovoBanco.createStatement();
                            String sql_cep = "select * from CF_LOJA where ID_LOJA = '" + rset.getInt("CODLOJA") + "'";
                            Statement stmtConsulta = connNovoBanco.createStatement(ResultSet.TYPE_SCROLL_INSENSITIVE, ResultSet.FETCH_FORWARD);
                            ResultSet rs = stm.executeQuery(sql_cep);
                            aux_loja = (Integer)rset.getInt("CODLOJA");
                            if (rs.next()) {
                                /** se encontrar algum resultado nesta busca entra no if */
                                /** dentro deste bloco vc seta o id da LOJA encontrado */
                                aux_loja = rs.getInt("ID_LOJA");
                                //hmTurno.put("CODLOJA", rs.getInt("ID_LOJA"));
                            } else {
                                /** Se nao encontrar nenhum resultado na sua busca entra neste else */
                                /** seta o id da LOJA padrão dentro deste bloco */
                                aux_loja = 9999;
                                //hmTurno.put("CODLOJA", 9999);
                            }
                            stmtConsulta.close();
                            stm.close();
                            sql_cep = null;
                        }
                        if (rset.getString("CODUSUARIO") != null) {
                            Statement stm = connNovoBanco.createStatement();
                            String sql_cep = "select * from CD_USUARIO where ID_USUARIO = '" + rset.getInt("CODUSUARIO") + "'";
                            Statement stmtConsulta = connNovoBanco.createStatement(ResultSet.TYPE_SCROLL_INSENSITIVE, ResultSet.FETCH_FORWARD);
                            ResultSet rs = stm.executeQuery(sql_cep);
                            aux_usuario = (Integer)rset.getInt("CODUSUARIO");
                            if (rs.next()) {
                                /** se encontrar algum resultado nesta busca entra no if */
                                /** dentro deste bloco vc seta o id do USUARIO encontrado */
                                aux_usuario = rs.getInt("ID_USUARIO");
                                //hmTurno.put("CODUSUARIO", rs.getInt("ID_USUARIO"));
                            } else {
                                /** Se nao encontrar nenhum resultado na sua busca entra neste else */
                                /** seta o id do USUARIO padrão dentro deste bloco */
                                aux_usuario = 9999;
                                //hmTurno.put("CODUSUARIO", 9999);
                            }
                            stm.close();
                            stmtConsulta.close();
                            sql_cep = null;
                        }
                    } catch (SQLException c) {
                        JOptionPane.showMessageDialog(null, c);
                    }
                }
                if (rset.getString("CODPROD") == null) {
                    aux_codprod = 999;
                    }
                if (rset.getString("CODPROD") != null) {
                    if (rset.getString("CODPROD").equals("")) {
                        aux_codprod = 999;
                      }
                }
                if (rset.getString("CODLOJA") == null) {
                    aux_loja = 9999;
                    //Se o codloja que vem do Turno for nulo, coloca o id da loja padrão
                }
                if (rset.getString("CODLOJA") != null) {
                    if (rset.getString("CODLOJA").equals("")) {
                        aux_loja = 9999; //Se o codloja que vem do Turno for nulo, coloca o id da loja padrão
                     }
                }
                if (rset.getString("CODUSUARIO") == null) {
                    aux_usuario = 9999;
                    }
                if (rset.getString("CODUSUARIO") != null) {
                    if (rset.getString("CODUSUARIO").equals("")) {
                        aux_usuario = 9999;
                       }
                }
            } catch (SQLException Erro) {
                JOptionPane.showMessageDialog(null, "Erro " + Erro);
            }
            try {
                String sql_prov = "INSERT INTO VD_TURNO VALUES (" + "'" +
                        rset.getInt("CODTURNO") + "','" +
                        aux_usuario + "','" +
                        aux_codprod + "','" +
                        aux_loja + "','" +
                        rset.getFloat("ABERTURA") +"','" +
                        rset.getFloat("FECHAMENTO") + "','" +
                        rset.getFloat("AFERICAO") + "','" +
                        rset.getTimestamp("DTABERTURA") + "','" +
                        rset.getTimestamp("DTFECHAMENTO") + "')";
                stmt = connNovoBanco.prepareStatement(sql_prov);
               
                stmt.execute(sql_prov);
                System.out.println("Turno:" + (Integer) rset.getInt("CODTURNO") + " Produto: " + (Integer) rset.getInt("CODPROD") + "  Abertura: " + (Timestamp) rset.getTimestamp("DTABERTURA") + " Fechamento: " + (Timestamp) rset.getTimestamp("DTFECHAMENTO") + " FOI INSERIDO!" + "  Registro --> Nº " + cont_aux);
                sql_prov = null;
            } catch (SQLException ex) {
                ex.printStackTrace();
                JOptionPane.showMessageDialog(null, "Exceção: " + ex + "\n Ao inserir dados na tabela: 'CD_Turno'!" + "Classe: " + this.getClass().toString());
            } finally {
                try {
                    //stmtConsulta.close();
                    connNovoBanco.commit();
                } catch (SQLException ex1) {
                    ex1.printStackTrace();
                    JOptionPane.showMessageDialog(null, "Erro de exceção: " + ex1 + " na verificação da tabela: 'CD_Turno'!" + "Classe: " + this.getClass().toString());
                }

            }
            
            cont_aux = cont_aux + 1;
          }
            stmt.close();

    } catch (SQLException ex) {
        Logger.getLogger(teste_turno.class.getName()).log(Level.SEVERE, null, ex);
    }

System.out.println("\n\n Foram inseridos " + (cont_aux-1) + " registros.\n\n");

           
    }

Essa função está apresentando os problemas de lentidão e estouro de memória ja citados.

R

Olá pessoal.

Consegui resolver parte dos problemas. Passei alguns dos tratamentos que faço direto para sentença sql de busca e alterei o fechamento dos Statements e o consumo de memória diminuiu bastante. Porém, o desempenho continua não sendo satisfatório. Como disse antes, demora entre 15 e 20 minutos para migrar os dados de uma tabela com aproximadamente 40 mil registros.

Alguém teria alguma idéia melhor de como fazer isso. Lembrando que preciso fazer tratamentos e verificações dos dados que vem da base Firebird antes de gravar no MySQL.

Desde já, agradeço a atenção.

R

Olá pessoal.

Consegui resolver o problema.

Dentro do while uso o ps.addBatch.

Logo que sai do while uso o ps.executeBatch.

Também setei a conexão para não comitar automaticamente (conn.setAutoCommit(false)) e logo após o ps.executeBatch, é so dar o conn.commit().

Dessa forma, a conversão da tabela ja citada que estava demorando cerca de 20 minutos caiu para 1 minuto e 30 segundos.

Sei que pode ser mais rápido que isso, mas esse valor já está dentro do aceitável.

Agradeço a todos que ajudaram.

Criado 9 de setembro de 2010
Ultima resposta 5 de out. de 2010
Respostas 13
Participantes 5