Dúvida com performance Maps encadeados

14 respostas
D

Bom dia pessoal!

Estou fazendo refactor para melhora de performance em umas classes e gostaria de saber a opinião de vocês quanto ao seguinte caso:

Tenho uma aplicação responsável por ler milhares de dados do BD e de arquivos, agrupá-los por determinadas configurações da aplicação e tratar esses dados agrupados gerando relatórios.
Na solução criada hoje, os dados são agrupados utilizando-se Map dentro de Map.
Por exemplo, é necessário agrupar os dados por funcionário , produto e classe do produto.
Sendo assim existe um Map da seguinte forma:

Map<String, Map<String, Map<String, List<objeto> >>>

Sendo que a chave do primeiro Map é o funcionário, do segundo o produto e do terceiro a classe do produto.
Lembrando que existem milhares de registros, vocÊs acham que seria melhor criar apenas um Map<String, Lis<objeto>> onde a chave seria funcionário, produto e classe do produto separados por algum delimitador e utlizar split da String quando necessário?

14 Respostas

Rodrigo_Sasaki

Você não acha melhor criar as classes Funcionario, Produto e etc, e associá-las de um jeito que faça sentido?

Esse aí parece um código bem difícil de manter.

Em questão de performance, tudo vai depender das operações que você realiza em cima da estrutura.

D

Eu tenho informações em banco e informações em arquivo onde devo mesclar essas informações, agrupar e processar o agrupamento de acordo com diversas regras.
É um processo em batch que processa alguns valores para esses agrupamentos, salva em banco e gera arquivos de log…

Ao ler os registros do banco, o objetos retornados já contem essas informações ( funcionário, produto , etc) eu não preciso de classes para eles… já tenho em mãos.
Um exemplo, a consulta me retorna objetos com essas informações e mais n outras:
Funcionário: Danilo
Produto : (UM NUMERO DE TELEFONE)
Classe: celular
Valor: 100


Terei que agrupar por essas chaves e fazer cálculos com o valor e outros campos, de acordo com configurações xml feitas pelo usuário.

Rodrigo_Sasaki

Bom, caindo para o lado de performance de novo, já que não haverão classes, tudo depende do que você faz com isso tudo.

Eu acho que é melhor deixar como está. Adicionar tratamento de Strings no meio não deve ajudar, mas se é algo crítico, eu faria alguns testes.

D

Ficar criando diversos mapas para inserir dados e depois percorrer diversos mapas para ler dados não seria pior?

Rodrigo_Sasaki

danilocsf:
Ficar criando diversos mapas para inserir dados e depois percorrer diversos mapas para ler dados não seria pior?

Então, é muito difícil dizer. Provavelmente consumiria mais memória, agora isso nem sempre quer dizer que vai ficar mais lento.

Se eu fosse você eu faria uns testes, porque no outro cenário, você teria que concatenar Strings, e depois quebrá-las também. Tem que ver qual dos 2 é menos pior :slight_smile:

D

Exemplo de como é lido os dados e agrupados:

public Map<String, Map<String, List<ItemFaturamentoGeneric>>> findItensByInvoiceIdsAndCategory(List<Long> invoiceIds,
        String category, EnumItemFaturamento itemFaturamento) throws Exception{
        
        ItensCommonDAO dao = getItemDAO(itemFaturamento);        
        List<ItemFaturamentoGeneric> list = dao.findItensByInvoiceIdCategory(invoiceIds, category);
        Map<String, Map<String, List<ItemFaturamentoGeneric>>> result = new HashMap<String, Map<String, List<ItemFaturamentoGeneric>>>();
        Map<String, List<ItemFaturamentoGeneric>> keptDescriptions = null;
        List<ItemFaturamentoGeneric> listItens = null;
        
        if(list != null && !list.isEmpty()){
        
            for(ItemFaturamentoGeneric item : list){
                String product = item.getOriginTerminalNumber();
                String serviceDescription= item.getServiceDescription();
                
                
                keptDescriptions = result.get(product);
                if(keptDescriptions == null){
                    keptDescriptions = new HashMap<String, List<ItemFaturamentoGeneric>>();
                }
                
                listItens = keptDescriptions.get(serviceDescription);
                
                if(listItens == null){
                    listItens = new ArrayList<ItemFaturamentoGeneric>();
                }
                
                listItens.add(item);
                keptDescriptions.put(serviceDescription, listItens);
                result.put(product, keptDescriptions);
               
            }
            
        }
        
        return result;
    }
D

É que está numa situação complicada para testar agora.
Qualquer alteração que eu faça terá grande impacto em diversas partes do sistema e tem prazo curto.
Então eu teria que alterar já estando certo de que seria um ganho.

Rodrigo_Sasaki

É, infelizmente quando falamos de performance nós temos que testar.

Não estou dizendo pra você mexer no código que está em produção, mas faça algo separado, com uma massa de dados de tamanho relevante, e teste as 2 técnicas. Eu sinceramente não sei dizer qual seria mais rápido.

fabim

Nao seria melhor (e muito mais performatico) vc simplesmente ler tudo, gravar tudo em 3 tabelas temporarias, e depois trazer tudo num select com JOIN + ORDER BY?

D

fabim
Desculpa, não entendi…

Eu já estou lendo tudo o que preciso, porque e o que colocaria em tabelas temporárias?

fabim

Digamos que vc nao leu nada ainda…
Se eu entendi, vc tem 2 universos distintos (banco + files) e precisa unir os 2. Entao primeiro façamos isso:

  • INSERT AS SELECT, numa temp de funcionario, com os funcionarios que vc precisa + INSERT DO QUE LER NOS ARQUIVOS DE FUNCIONARIO
  • INSERT AS SELECT, numa temp de produto, com os produtos q vc precisa + INSERT DO QUE LER NOS ARQUIVOS DE PRODUTO
  • INSERT AS SELECT, numa temp de classe, com as classes que vc precisa + INSERT DO QUE LER NOS ARQUIVOS CLASSE

Agora vc vai fazer apenas uma leitura:

SELECT FROM FUNCIONARIO_TMP JOIN PRODUTO_TMP ON () JOIN CLASSE_TMP ON () ORDER

Pronto vc nem precisa usar map pra nada.

D

Então fabim, a situação não é bem essa…
Cada linha dos registros do BD eu tenho funcionario , produto e classe (por exemplo) e outros valores.
Cada linha do arquivo, eu terei esses mesmos dados e outros também…
Tenho que agrupar os dados por estas chaves para realizar determinados processamentos, unindo registros do arquivo e do bd … é bem complexo pra explicar a regra de negócio…
Eu não poderia fazer um group by pois tenho outros valores nos registros que eu preciso dos valores isolados , de cada registro.
Então o agrupamento ficaria por conta do Java mesmo.
Eu não tenho essa situação que colocaria somente funcionarios, produtos ou outra coisa em uma tabela temporária.
Não sei se estou sendo claro…
Em um registro lido eu tenho, supondo:
Funcionario, Produto, Classe do produto, Valor, Categoria, Unidade organizacional, Data de utilizacao, localidade …

Então tenho que agrupar, por exemplo, por funcionario, produto e classe e fazer alterações no valor de acordo com a unidade organizacional e localidade por exemplo. Obterei também os dados lidos do arquivo que coincidam as chaves , e farei alterações em algum outro campo do registro de acordo com algum campo do arquivo… entendeu mais ou menos?
Acho que a solução é agrupar no código mesmo… porém como são muitos dados, muito processamento e muitas possibilidades, a performance ta um pouco ruim, e achei que um dos pontos a se melhorar seria diminuir a quantidade de mapas criados…

fabim

Então que tal vc ter 1 TreeMap de objetos funcionario, dentro de cada objeto funcionario um TreeMap de Produtos, e dentro de cada objeto produto um TreeMap de Classes?

Da pra fazer uma logica de ler sequencialmente esses registros (que tem todas as informacoes) e popular esses caras.

D

Então, mas eu não tenho um objeto funcionário, um objeto produto e etc…
São todos uma String.
Funcionário é uma matrícula, produto um número de telefone e por ai vai…
Os registros retornados da consulta ao BD são uma coleção de um objeto que possui apenas tipos primitivos e String, BigDecimal…

E o esquema de TreeMap que você falou me parece com a solução que está desenvolvida hoje concorda?
Tenho Map dentro de Map…

Criado 3 de julho de 2013
Ultima resposta 3 de jul. de 2013
Respostas 14
Participantes 3