Oracle
 sql >> Base de Dados >  >> RDS >> Oracle

INSERT de 10 milhões de consultas em 10 minutos no Oracle?


Eu sei que outros já mencionaram isso e você não quer ouvir, mas use SQL*Loader ou tabelas externas. Meu tempo médio de carregamento para tabelas com aproximadamente a mesma largura é de 12,57 segundos para linhas de pouco mais de 10m. Esses utilitários foram explicitamente projetados para carregar dados no banco de dados rapidamente e são muito bons nisso. Isso pode incorrer em algumas penalidades de tempo adicionais, dependendo do formato do seu arquivo de entrada, mas existem algumas opções e raramente tive que alterar os arquivos antes de carregar.

Se você não estiver disposto a fazer isso, não precisará atualizar seu hardware ainda; você precisa remover todos os impedimentos possíveis para carregar isso rapidamente. Para enumerá-los, remova:
  1. O índice
  2. O acionador
  3. A sequência
  4. A partição

Com tudo isso, você está obrigando o banco de dados a realizar mais trabalho e, como está fazendo isso de forma transacional, não está usando o banco de dados em todo o seu potencial.

Carregue os dados em uma tabela separada, digamos ABC_LOAD . Após o carregamento completo dos dados, execute um único INSERT no ABC.
insert into abc
select abc_seq.nextval, a.*
  from abc_load a

Ao fazer isso (e mesmo que não o faça), certifique-se de que o tamanho do cache de sequência esteja correto; citar:

Quando um aplicativo acessa uma sequência no cache de sequência, esses números de sequência são lidos rapidamente. No entanto, se um aplicativo acessar uma sequência que não está no cache, a sequência deverá ser lida do disco para o cache antes que os números de sequência sejam usados.

Se seus aplicativos usam muitas sequências simultaneamente, seu cache de sequência pode não ser grande o suficiente para conter todas as sequências. Nesse caso, o acesso a números de sequência pode exigir leituras de disco. Para acesso rápido a todas as sequências, certifique-se de que seu cache tenha entradas suficientes para conter todas as sequências usadas simultaneamente por seus aplicativos.

Isso significa que, se você tiver 10 threads gravando simultaneamente 500 registros, cada um usando essa sequência, precisará de um tamanho de cache de 5.000. O documento ALTER SEQUENCE indica como alterar isso:
alter sequence abc_seq cache 5000

Se você seguir minha sugestão, eu aumentaria o tamanho do cache para algo em torno de 10,5 m.

Veja como usar a dica APPEND (veja também Oracle Base); isso instrui o Oracle a usar uma inserção de caminho direto, que anexa os dados diretamente ao final da tabela, em vez de procurar espaço para colocá-los. Você não poderá usar isso se sua tabela tiver índices, mas poderá usá-lo em ABC_LOAD
insert /*+ append */ into ABC (SSM_ID, invocation_id , calc_id, ... )
select 'c','b',NULL, 'test', 123 , 'N', 'asdf' from dual
union all select 'a','b',NULL, 'test', 123 , 'N', 'asdf' from dual
union all select 'b','b',NULL, 'test', 123 , 'N', 'asdf' from dual
union all select 'c','g',NULL, 'test', 123 , 'N', 'asdf' from dual

Se você usar a dica APPEND; Eu adicionaria TRUNCATE ABC_LOAD depois de inserir em ABC caso contrário, esta tabela crescerá indefinidamente. Isso deve ser seguro, pois você terá terminado de usar a tabela até então.

Você não menciona qual versão ou edição ou Oracle está usando. Há uma série de pequenos truques extras que você pode usar:

  • Oráculo 12c

    Esta versão oferece suporte a colunas de identidade; você poderia se livrar da sequência completamente.
    CREATE TABLE ABC(
       seq_no         NUMBER GENERATED AS IDENTITY (increment by 5000)
    

  • Oracle 11g r2

    Se você mantiver o gatilho; você pode atribuir o valor de sequência diretamente.
    :new.seq_no := ABC_seq.nextval;
    

  • Oracle Enterprise Edition

    Se você estiver usando o Oracle Enterprise, poderá acelerar o INSERT em ABC_LOAD usando a dica PARALELA:
    insert /*+ parallel */ into abc
    select abc_seq.nextval, a.*
      from abc_load a
    

    Isso pode causar seus próprios problemas (muitos processos paralelos, etc), então teste. Ele pode ajuda para as inserções de lote menores, mas é menos provável que você perca tempo calculando qual thread deve processar o quê.

tl;dr


Use os utilitários que acompanham o banco de dados.

Se você não puder usá-los, livre-se de tudo que possa tornar a inserção lenta e faça isso em massa, porque é nisso que o banco de dados é bom.