Aggiorna tutte le righe


12

Voglio conoscere il modo più efficiente per aggiornare ogni riga in una tabella Oracle estremamente grande per una singola colonna. Per esempio:

update mytable set mycolumn=null;

o:

update mytable set mycolumn=42;

La mia conoscenza potrebbe benissimo essere viziata. Quello che faccio è modificare la tabella per eliminare la colonna. Quindi, modifico la tabella per aggiungere la colonna con un valore predefinito del nuovo valore che voglio usare. Quindi, modifico la tabella per rimuovere il valore predefinito per la colonna. Trovo che sia molto più veloce di un semplice aggiornamento, ma ho la sensazione che esista un metodo migliore.


Per quanto ho capito, l'aggiunta di una nuova colonna non nulla con un valore predefinito è una modifica dei metadati solo in Oracle. Dubito che avranno ottimizzato il caso "aggiorna tutte le righe allo stesso valore". È un'operazione comune per te?
Martin Smith,

1
Prova entrambi i metodi e cronometri. Cosa ti impedisce di farlo? Ecco il fatto che devi finire con lo stesso risultato, non con un risultato diverso! Altrimenti, il confronto non è valido.
tvCa

@tvCa Ho provato in entrambi i modi. Se faccio solo un aggiornamento, funziona per circa due ore e poi lo uccido. Se lascio cadere una colonna, ci vogliono solo pochi secondi. L'aggiunta di una colonna senza un valore predefinito (che annulla la colonna) richiede solo pochi secondi. L'aggiunta di una colonna con un valore predefinito richiede circa 30 minuti. Quindi, se voglio, ad esempio, impostare tutti i valori di una colonna su "Some Value", attualmente trascino e aggiungo la colonna. Voglio solo sapere se esiste un modo più veloce per farlo.
Kainaw,

2
Stai usando 11gR2? @MartinSmith è corretto. Vedi qui per una descrizione su come aggiungere la nuova colonna con un DEFAULT come NOT NULL è una modifica molto più rapida rispetto all'aggiunta come NULL, che forzerà un aggiornamento di tutte le righe nella tabella (proprio come l'emissione di un'istruzione UPDATE). Il problema che vedo è la rimozione del valore DEFAULT in seguito, poiché l'aumento delle prestazioni deriva dalla memorizzazione di DEFAULT nel dizionario. A quel punto dovrai anche affrontare il vincolo NOT NULL.
rispondere al

Risposte:


2

Molto dipende dall'altra attività in corso su questa tabella mentre si sta eseguendo questo aggiornamento di massa. Spero che tu abbia una sorta di ambiente di test in cui puoi eseguire alcuni esempi di ciò che ti piacerebbe fare e avere un'idea di quale sia il modo migliore. Proverei:

  1. Esegui il singolo update table set column_name = blah;
  2. Crea un loop plSql per selezionare tutte le chiavi primarie nella tabella e scorrere tra loro, eseguendo il updating the column=blahcommit di tutti gli aggiornamenti X (forse 10000). È possibile parallelizzare questo codice copiandolo e facendolo copiare in una sezione separata di chiavi primarie.

Abbiamo avuto un problema molto simile con una tabella che è stata utilizzata molto attivamente nel sistema OLTP e siamo stati in grado di parallelizzarlo 5 volte e eseguito senza alcun impatto di blocco dell'utente su una tabella di righe 100+ MM che commetteva ogni 10000. Non hai detto come grande è il tuo tavolo o che tipo di applicazione stai eseguendo, ma questo tipo di soluzione potrebbe adattarsi a te.


0

Per un digiuno UPDATE, assicurati di non avere trigger che si attivano.

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

ALTER TABLE mytable DISABLE ALL TRIGGERS;

Assicurati di riattivare solo quelli che vuoi quando hai finito.

ALTER TRIGGER mytrigger ENABLE;

È inoltre possibile che si verifichi un sovraccarico della manutenzione dell'indice. Prova a ricostruire i tuoi indici separatamente. Per fare ciò, la risposta qui di pappes dovrebbe essere utile: /programming/129046/disable-and-later-enable-all-table-indexes-in-oracle

Sto ripetendo la risposta di pappes qui per riferimento. (Nota che questo comando SPOOL fa ipotesi sulla tua piattaforma 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

Importa ...

select 'alter index ' || u.index_name || ' rebuild online;'
  from user_indexes u;

-1

rimuovere l'indice. aggiorna la colonna. restituisce l'indice indietro. ma se la colonna contiene lo stesso valore per tutte le righe è possibile eliminare l'indice.


-2

Se non si hanno limitazioni di spazio, è possibile creare una nuova tabella, uguale alla tabella con la nuova colonna aggiunta a quella tabella ed eliminare la tabella precedente:

create new_table as
select old_table.*, (with or without default_Value) as new_column
from old_table;

1
Sarà più efficiente? Perché? E se ci fossero FK che fanno riferimento alla tabella esistente?
ypercubeᵀᴹ

Sì, puoi provarlo su un'altra tabella di esempio e vedere tu stesso il risultato. Se ci sono FK, non lo so esattamente ma è possibile disabilitarli e abilitarli se è efficiente.
E_Salamon,

-3

Prova più sequenze di aggiornamento / commit. L'inserimento / aggiornamento / eliminazione di troppe righe senza commit comporta un pesante carico di I / O. Può essere abbastanza ottimizzato conoscendo le dimensioni dei blocchi e le dimensioni e le cose dei record.

Per eliminare dati interi su una tabella, truncate table xè meglio di delete from x. Anche lo spurgo rende un altro carico di lavoro di processo.

Modifica: è possibile utilizzare l' inmemoryopzione, caricare la tabella in memoria in formato colonnare e quindi eseguire l'aggiornamento. dipende davvero dalle relazioni e dalla struttura del tuo DB. Si veda questo articolo .


3
Vogliono aggiornare una colonna della tabella. Non vedo come truncateo deletesarebbe di alcun aiuto.
ypercubeᵀᴹ

@ypercube Ho appena spiegato come la manipolazione di più dati senza commit porti a un carico IO indesiderato; sia update o altri OLTP.
Cunning

3
Potresti spiegare con quale frequenza gli commit riducono l' I / O? Non aumenterebbero l' I / O a causa dei checkpoint?
Mustaccio,

3
L'uso della terminologia non convenzionale ("tx journal", "flushes session") è un po 'confuso. Sia che tu utilizzi più transazioni brevi o una transazione massiccia, il volume totale dei record di ripristino generati sarà lo stesso. Le operazioni di I / O si verificano solo quando il buffer del registro di ripristino viene scritto sul disco (lasciando solo i punti di controllo della cache del buffer per ora), che si verifica al momento del commit o quando il buffer di ripristino è quasi pieno. Successivamente, se si commette frequentemente si causa I / O aggiuntivo, quindi mi chiedo come ciò possa ridurre l' I / O.
Mustaccio

4
Potresti voler leggere ciò che Tom Kyte ha da dire su "commit frequenti": asktom.oracle.com/pls/apex/… " è sbagliato, sbagliato, sbagliato. Così sbagliato .... Così molto molto sbagliato "
a_horse_with_no_name
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.