RESOLVIDO - JavaFX: TableView muito lenta

Pessoal, estou desenvolvendo um sistema em JavaFX, banco de dados MySQL e utilizando JDBC, porém ao desenvolver as primeiras telas estou me deparando com uma lentidão absurda no carregamento da TableView e dos dados nas telas.

Minhas tabelas possuem cerca de 5 mil registros e outras ultrapassam 10 milhões inclusive algumas com Blob imagens, porém a lentidão está até nas tabelas mais simples, vou postar aqui a estrutura apenas de uma tabela simples e que está bem lenta, por favor, poderiam avaliar se estou fazendo alguma coisa errada.

Segue abaixo estrutura BEAN (model), DAO e Controller do FXML:

Classe BEAN (model)

public class beanRECFornecedor {

    int cod;
    String codigo;
    String fornecedor;
    String contato;
    String planejador;

    @Override
    public String toString() {
        return "beanRECFornecedor{" + "cod=" + cod + ", codigo=" + codigo + ", fornecedor=" + fornecedor + ", contato=" + contato + ", planejador=" + planejador + '}';
    }

    public beanRECFornecedor() {
    }

    public beanRECFornecedor(int cod, String codigo, String fornecedor, String contato, String planejador) {
        this.cod = cod;
        this.codigo = codigo;
        this.fornecedor = fornecedor;
        this.contato = contato;
        this.planejador = planejador;
    }

    public int getCod() {
        return cod;
    }

    public void setCod(int cod) {
        this.cod = cod;
    }

    public String getCodigo() {
        return codigo;
    }

    public void setCodigo(String codigo) {
        this.codigo = codigo;
    }

    public String getFornecedor() {
        return fornecedor;
    }

    public void setFornecedor(String fornecedor) {
        this.fornecedor = fornecedor;
    }

    public String getContato() {
        return contato;
    }

    public void setContato(String contato) {
        this.contato = contato;
    }

    public String getPlanejador() {
        return planejador;
    }

    public void setPlanejador(String planejador) {
        this.planejador = planejador;
    }
}

Classe DAO (crud)

public class daoRECFornecedor {

//Metodo para retornar todas os registros da tabela (Read - C"R"UD) e preenche o TablView
    public ObservableList<beanRECFornecedor> obterTabelaCriterio(String Filtro1, String criterio1) {
        ObservableList<beanRECFornecedor> lista = FXCollections.observableArrayList();
        Connection conn = dbConexao.getConnection();
        Statement stmt = null;
        ResultSet rs = null;
        String sql = "SELECT * FROM fornecedor "
                + " WHERE " + Filtro1 + " LIKE '%" + criterio1 + "%' "
                + " ORDER BY fornecedor ASC";
        try {
            stmt = conn.createStatement();
            rs = stmt.executeQuery(sql);
            while (rs.next()) {
                beanRECFornecedor bean = new beanRECFornecedor();

                bean.setCod(rs.getInt("cod"));
                bean.setCodigo(rs.getString("codigo"));
                bean.setFornecedor(rs.getString("fornecedor"));
                bean.setContato(rs.getString("contato"));
                bean.setPlanejador(rs.getString("planejador"));

                lista.addAll(bean);
            }
        } catch (Exception e) {
            e.printStackTrace();
            dbConexao.close((com.mysql.jdbc.Connection) conn, stmt, rs);
        } finally {
            dbConexao.close((com.mysql.jdbc.Connection) conn, stmt, rs);
        }
        return lista;
    }
}

Controller do formulário FXML onde tem a table view

public class controlTelaRECFornecedor implements Initializable {
    daoRECFornecedor dao = new daoRECFornecedor();

    @FXML
    public TableView<beanRECFornecedor> tblViewFornecedor;
    @FXML
    private TableColumn<beanRECFornecedor, Integer> tblClmCod;
    @FXML
    private TableColumn<beanRECFornecedor, String> tblClmCodFornecedor;
    @FXML
    private TableColumn<beanRECFornecedor, String> tblClmFornecedor;
    @FXML
    private TableColumn<beanRECFornecedor, String> tblClmPlanejador;
    @FXML
    private TableColumn<beanRECFornecedor, String> tblClmContato;


    @FXML
    private JFXComboBox<String> txtFiltro1;
    @FXML
    private JFXTextField txtCriterio1;


    @Override
    public void initialize(URL url, ResourceBundle rb) {
	//Chama o método que inicializa o formulário preenchendo a Tableview
        carregaGrid();
    }

    //Carrega TableView (Utilizado na iniciação deste FXML)
    @FXML
    private void carregaGrid() {
        tblClmCod.setCellValueFactory(new PropertyValueFactory<>("cod"));
        tblClmCodFornecedor.setCellValueFactory(new PropertyValueFactory<>("codigo"));
        tblClmFornecedor.setCellValueFactory(new PropertyValueFactory<>("fornecedor"));
        tblClmPlanejador.setCellValueFactory(new PropertyValueFactory<>("planejador"));
        tblClmContato.setCellValueFactory(new PropertyValueFactory<>("contato"));
	
        ObservableList<beanRECFornecedor> bean = FXCollections.observableArrayList(dao.obterTabelaCriterio(txtFiltro1.getSelectionModel().getSelectedItem(), txtCriterio1.getText()));
        tblViewFornecedor.setItems(bean);
    }
}

A questão é você pensar em paginação tanto na TableView quanto na SQL.
E tambem certifique de saber se existe um indice criado no banco para consultas, caso contrario o motor do banco de dados terá de ler a tabela inteira.

1 curtida

Boa noite, criei paginacao em todas as telas, deu uma melhorada mas ainda continua lento, na tabela que tem campo Blob o Select é ainda mais demorado mesmo colocando “LIMIT 20” por exemplo demora uns 12 segundos pra trazer os dados na tela.

Poderia informar como funciona os indices? Crio ele no campo cod por exemplo da tabela e no Select informo ele em algum lugar?

12 segundos realmente é muito tempo. Os campos Blobs voce pode solicitar do banco apos alguma confirmação do usuario para ver esses dados.
Então acabará ficando rapido, porque primeiramente você carrega as informações magras da tabela.
Quanto as consultas SQL, o uso do like pode ser terrivel, mesmo em um campo indexado, pois terá de analisar o conteudo de um em um ate que satisfaça a condição.

O motor do banco sempre tenta fazer a otimização para o retorno, mas tem horas que tem que analisar sequencialmente e isso e’ osso.

Analisa ao certo o que você quer retornar do banco na consulta, então cria um indice no banco e deixa ele ir crescendo, usar order by na consulta sem ter esse indice previamente criado, significa que o banco criará na hora da query e isso tambem é terrivel para o que você quer.

Traga as informações por partes.

2 curtidas

Por outro lado, tenta imaginar um pool trabalhando em background (thread).
Nesse pool você vai alimentando ele com o retorno do banco e de acordo com a posição que o usuario esteja visualizando, então sempre ele traz uma sobra.
Agora imagina o TableView paginando esse retorno. Mas e’ improdutivo trazer todo o banco de milhoes de registros para o computador do usuario de uma vez.

Quando você faz a consulta direto no banco, ela demora também?

Se não, tente utilizar uma Thread para fazer a consulta, pois a JavaFX Application Thread (UI Thread ou Thread Principal) tem muita tarefas para fazer (ela fica em looping a todo momento realizando as terefas) e delegar a ela uma consulta de milhares de linhas pode congelar a sua aplicação.

O que eu sugiro:
Aplica o que o j-menezes passou como dica e tente fazer a consulta em uma Thread a parte

Se a consulta no banco já é lenta, tenta aplicar os índices (como o @j-menezes sugeriu).
Digite o nome do seu editor SQL no google e escreve Create Index

Ex: DBeaver Create Index

Ou então vê se não tem como melhorar a consulta

Se for uma consulta que envolve diversos cálculos e relacionamentos, talvez seja bom criar uma tabela de BI, ou seja, essa tabela já é persistida com o calculo e com o relacionamento feito. Ai só é necessário fazer o select e colocar um where para filtrar

Abraços

1 curtida

Obrigado pela ajuda, porém acabei identificando que a demora em carregar a tela não é devido a consulta e carregamento o TableView e sim devido a própria tela FXML do JavaFX, agora estou tentando descobrir o porque demora tanto para carregar a tela, vou abrir um novo topico para este tema, obrigado.