Atualização / inserção em massa do banco de dados do arquivo CSV

8

Estou implementando o recurso de importação de dados específicos do aplicativo de um banco de dados para outro.

Eu tenho um arquivo CSV contendo, digamos, 10000 linhas. Essas linhas precisam ser inseridas / atualizadas no banco de dados.

Pode ser o caso, em que algumas linhas podem aparecer no banco de dados, o que significa que essas precisam ser atualizadas. Se não estiver presente no banco de dados, eles precisam ser inseridos.

Uma solução possível é que eu posso ler uma por uma linha, verificar a entrada no banco de dados e criar consultas de inserção / atualização de acordo. Mas esse processo pode levar muito tempo para criar consultas de atualização / inserção e executá-las no banco de dados. Algumas vezes meu arquivo CSV pode ter milhões de registros.

Existe alguma outra maneira mais rápida de conseguir esse recurso?


fonte
Tente processá-lo em partes, caso contrário, uma grande leitura de CSV de uma só vez resultará OutOfMemory!
@TheNewIdiot que não acontecerá se estiver usando memória suficiente como um servidor decente que destine pelo menos 2 GB de RAM à JVM. Também dependerá do tipo de dados no arquivo CSV e se o processo será executado em um único processo ou próximo a outro processado no servidor.
@Luiggi Mendoza: Eu concordo com você. Temos memória suficiente para processar o grande arquivo CSV em produção.

Respostas:

7

Existe uma boa tecnologia disponível no Oracle chamada External Tables. No seu cenário, você pode acessar seus dados externos em texto sem formatação usando Tabelas Externas de dentro do banco de dados e atualizar seus dados existentes no banco de dados com instruções SQL que você ama e que está acostumado - por exemplo INSERT, MERGEetc.

Na maioria dos casos, o uso de utilitários fornecidos pela Oracle é a melhor maneira de executar ETL. E como sua pergunta parece mais administrativa, sugiro que você analise minha postagem anterior no DBA Stack Exchange "Atualizar banco de dados Oracle de CSV" .

ATUALIZAÇÃO: Essa abordagem funciona muito bem para a leitura de dados externos no banco de dados. Geralmente, você define o formato de dados externos toda vez que precisar processar o arquivo de texto sem formatação que possui um novo formato. Depois que a tabela externa é criada, você pode consultá-la como uma tabela de banco de dados real. Sempre que houver novos dados para importar, basta substituir o (s) arquivo (s) subjacente (s) em tempo real, sem a necessidade de recriar tabelas externas. Como a tabela externa pode ser consultada como qualquer outra tabela do banco de dados, você pode escrever instruções SQL para preencher outras tabelas do banco de dados.

A sobrecarga do uso de tabelas externas geralmente é menor em comparação com outras técnicas que você implementaria manualmente, porque essa tecnologia foi projetada com o desempenho em mente, levando em consideração a arquitetura do banco de dados Oracle.

Yasir Arsanukaev
fonte
Concordo que esta é uma das soluções para alcançar meu objetivo. Como essa abordagem pode ser adequada para o processamento dinâmico de CSV? Significa que meu usuário do aplicativo tem a oportunidade de fazer upload de vários arquivos com diferentes formatos (nesse caso, contos externos precisam ser criados em tempo real). Além disso, um arquivo CSV pode conter dados que precisam ser preenchidos em várias tabelas.
1

Eu acho que você deve usar o SQL * Loader para carregar o arquivo CSV na tabela temporária e, em seguida, use a instrução MERGE para inserir dados na tabela de trabalho.
O SQL * Loader lhe dará mais flexibilidade do que as tabelas externas e, se alguém usar o carregamento direto do caminho, será muito rápido. E o MERGE fará exatamente o que você precisa - INSERIR novos registros e ATUALIZAR os existentes.
Alguns links para iniciar:
http://docs.oracle.com/cd/B19306_01/server.102/b14215/ldr_concepts.htm
http://docs.oracle.com/cd/B28359_01/server.111/b28286/statements_9016 .htm

Mindaugas Riauba
fonte
11
Quando você carrega dados no banco de dados usando o SQL Loader, o processo DBWR ou o processo SQL Loader grava buffers nos arquivos de dados. Quando você move posteriormente os dados carregados para outras tabelas, o banco de dados executa outra E / S. Eu não acho que esse trabalho extra possa ser justificado. A propósito, quando External Tables utiliza o driver ORACLE_LOADER, a sintaxe para definir o formato dos dados de entrada é a mesma usada pelo utilitário sqlldr, porque essencialmente elas são a mesma tecnologia e, portanto, podem ser usadas de forma intercambiável. Mesas externas neste cenário é preferível uma vez que não há necessidade de dados primeira carga no banco de dados
Yasir Arsanukaev
Como resposta habitual é "depende" :). No nosso caso, geralmente é mais conveniente carregar na tabela temporária primeiro e processar depois. Como o carregamento direto do caminho não gera refazer essa E / S adicional é quase imperceptível entre outras operações. Em outros casos, é claro, outros métodos serão melhores.
Mindaugas Riauba
0

PreparedStatements tornará a criação de consultas de inserção ou atualização muito rápida. Você deve ter três PreparedStatements: um para inserção, um para atualização e outro para verificar se a linha já está na tabela. Se você conseguir manter os IDs iguais entre o arquivo CSV e o novo banco de dados, verificar se uma linha está presente usando o campo primaryID também deve ser muito rápido.

O uso de uma inserção em lote pode oferecer um ganho de desempenho. À medida que você transmite o arquivo CSV, você verifica se a linha já está lá e então faz uma atualização ou adiciona a linha ao comando de inserção em lote. Você deve verificar esta questão do SO para comparar a velocidade dessas duas abordagens.

Se essa importação de banco de dados é algo que precisa ser feito regularmente e o desempenho é um problema usando o método descrito acima, você pode tentar manipular a tarefa com vários segmentos de trabalho. Use quantos threads forem processadores na máquina executando esse código.

  int nThreads = Runtime.getRuntime().availableProcessors();

Cada encadeamento obtém sua própria conexão com o banco de dados e, à medida que o código percorre o arquivo, as linhas do CSV podem ser transferidas para os diversos encadeamentos. Isso é muito mais complicado, então eu faria isso apenas se os requisitos de desempenho me obrigassem.

Comunidade
fonte
Obrigado pela sua resposta. Novamente, isso exigirá análise e preenchimento de arquivos CSV em instruções preparadas. Com a abordagem 'Tabelas externas', vejo que a análise de arquivos pode ser movida para o lado do banco de dados, onde o aplicativo não precisa se preocupar com isso. Além disso, estou usando o JPA com o Hibernate no meu aplicativo. Estou procurando a opção que pode ser a combinação de JPA / Hibernate / Oracle, que facilita a análise de arquivos, o bom desempenho, a manutenção e a flexibilidade.