Atualizar todas as linhas

12

Quero saber a maneira mais eficiente de atualizar todas as linhas em uma tabela Oracle extremamente grande para uma única coluna. Por exemplo:

update mytable set mycolumn=null;

ou:

update mytable set mycolumn=42;

Meu conhecimento pode muito bem ser obsoleto. O que faço é alterar a tabela para soltar a coluna. Em seguida, altero a tabela para adicionar a coluna com um valor padrão do novo valor que quero usar. Em seguida, altero a tabela para remover o valor padrão da coluna. Acho que isso é muito mais rápido do que apenas executar uma atualização, mas sinto que existe um método melhor.

kainaw
fonte
Tanto quanto eu entendo, adicionar uma nova coluna não nula com um padrão é apenas uma alteração de metadados no Oracle. Duvido que eles tenham otimizado o caso "atualizar todas as linhas com o mesmo valor". Esta é uma operação comum para você?
Martin Smith
1
Apenas tente ambos os métodos e cronometre-os. O que está impedindo você de fazer isso? Eis que você deve terminar com o mesmo resultado, não com um resultado diferente! Caso contrário, a comparação é inválida.
TvCa
@tvCa Eu tentei nos dois sentidos. Se eu apenas fizer uma atualização, ela será executada por cerca de duas horas e eu a mato. Se eu soltar uma coluna, leva apenas alguns segundos. Adicionar uma coluna sem um valor padrão (que anula a coluna) leva apenas alguns segundos. Adicionar uma coluna com um valor padrão leva cerca de 30 minutos. Portanto, se eu quiser, por exemplo, definir todos os valores em uma coluna como 'Some Value', atualmente solto e adiciono a coluna. Eu só quero saber se existe uma maneira mais rápida de fazer isso.
kainaw
2
Você está usando 11gR2? @MartinSmith está correto. Consulte aqui para obter uma descrição de como adicionar a nova coluna com DEFAULT como NOT NULL é uma alteração muito mais rápida do que adicioná-la como NULL, o que forçará uma atualização de todas as linhas da tabela (assim como a emissão de uma instrução UPDATE). O problema que vejo é remover o valor PADRÃO posteriormente, porque o aumento de desempenho vem do armazenamento do PADRÃO no dicionário. Você também terá que lidar com a restrição NOT NULL nesse ponto.
precisa saber é

Respostas:

2

Depende muito das outras atividades realizadas nessa tabela enquanto você realiza esta atualização em massa. Espero que você tenha algum tipo de ambiente de teste em que possa executar algumas amostras do que gostaria de fazer e ter uma idéia de qual é o melhor. Eu tentaria:

  1. Execute o single update table set column_name = blah;
  2. Crie um loop plSql para selecionar todas as chaves primárias na tabela e faça um loop entre elas, updating the column=blahe confirme todas as atualizações do X (talvez 10000). Você pode paralelizar esse código copiando-o e fazendo-o copiar em uma seção separada das chaves primárias.

Tínhamos um problema muito semelhante com uma tabela que era muito ativamente usada no sistema OLTP e conseguimos paralelá-la 5x e executada sem impacto de bloqueio do usuário em uma tabela de linha com mais de 100 MM que confirmava a cada 10000. Você não disse como sua mesa é grande ou que tipo de aplicativo você está executando, mas esse tipo de solução pode se adequar a você.

Pete Hagerty
fonte
0

Para um jejum UPDATE, verifique se você não tem nenhum gatilho que esteja disparando.

SELECT trigger_name, status FROM user_triggers WHERE table_name = 'MYTABLE';

ALTER TABLE mytable DISABLE ALL TRIGGERS;

Certifique-se de reativar apenas os que deseja quando terminar.

ALTER TRIGGER mytrigger ENABLE;

Você também pode estar executando a sobrecarga da manutenção do índice. Tente recriar seus índices separadamente. Para fazer isso, a resposta aqui pelo pappes deve ser útil: /programming/129046/disable-and-later-enable-all-table-indexes-in-oracle

Estou repetindo a resposta dos pappes aqui para referência. (Observe que este comando SPOOL faz suposições sobre sua plataforma e ambiente.)

set pagesize 0    
alter session set skip_unusable_indexes = true;
spool c:\temp\disable_indexes.sql
select 'alter index ' || u.index_name || ' unusable;' from user_indexes u;
spool off
@c:\temp\disable_indexes.sql

Importar ...

select 'alter index ' || u.index_name || ' rebuild online;'
  from user_indexes u;
durette
fonte
-1

remova o índice. atualize a coluna. retornar o índice de volta. mas se a coluna contiver o mesmo valor para todas as linhas, você poderá eliminar o índice.

tatskie
fonte
-2

Se você não tiver limitação de espaço, poderá criar uma nova tabela, igual à sua tabela com sua nova coluna adicionada a essa tabela e excluir a tabela antiga:

create new_table as
select old_table.*, (with or without default_Value) as new_column
from old_table;
E_Salamon
fonte
1
Isso será mais eficiente? Por quê? E se houver FKs que façam referência à tabela existente?
ypercubeᵀᴹ
sim, você pode experimentá-lo em outra tabela de amostra e ver o resultado você mesmo. Se houver FKs, não sei exatamente, mas você pode desativá-los e ativá-los se for eficiente.
E_Salamon
-3

Tente várias seqüências de atualização / confirmação. Inserir / Atualizar / Excluir muitas linhas sem confirmação leva a uma carga pesada de E / S. Ele pode ser bastante otimizado, sabendo o tamanho dos blocos e os tamanhos dos registros.

Para excluir dados inteiros em uma tabela, truncate table xé melhor que delete from x. A limpeza também gera outra carga de trabalho do processo.

Editar: você pode usar a inmemoryopção, carregando a tabela na memória em formato colunar e, em seguida, faça a atualização. realmente depende dos relacionamentos e da estrutura do seu banco de dados. Veja este artigo .

Destreza
fonte
3
Eles querem atualizar uma coluna da tabela. Não vejo como truncateou deleteseria de alguma ajuda.
precisa saber é o seguinte
@ypercube Acabei de explicar como a manipulação de dados múltiplos sem confirmação leva a carga de E / S indesejada; seja atualização ou outros OLTP s.
Astúcia
3
Você poderia explicar com que frequência as confirmações reduzem a E / S? Eles não aumentariam a E / S por causa dos pontos de verificação?
mustaccio
3
Seu uso de terminologia não convencional ("diário de câmbio", "libera sua sessão") é um pouco confuso. Se você usa várias transações curtas ou uma transação maciça, o volume total de registros refazer gerados será o mesmo. As operações de E / S ocorrem apenas quando o buffer de redo log é gravado no disco (deixando apenas os pontos de verificação do cache do buffer por enquanto), o que acontece na confirmação ou quando o buffer de redo está quase cheio. Posteriormente, se você confirmar com frequência, causa E / S adicionais, então estou pensando em como isso pode reduzir a E / S.
Mustaccio
4
Você pode querer ler o que Tom Kyte tem a dizer sobre "commits frequentes": asktom.oracle.com/pls/apex/... " é errado, errado, errado Tão errado .... Então, muito, muito errado. "
a_horse_with_no_name