Perbarui semua baris

12

Saya ingin tahu cara paling efisien untuk memperbarui setiap baris dalam tabel Oracle yang sangat besar untuk satu kolom. Sebagai contoh:

update mytable set mycolumn=null;

atau:

update mytable set mycolumn=42;

Pengetahuan saya mungkin basi. Yang saya lakukan adalah mengubah tabel untuk menjatuhkan kolom. Lalu, saya mengubah tabel untuk menambahkan kolom dengan nilai default dari nilai baru yang ingin saya gunakan. Lalu, saya mengubah tabel untuk menghapus nilai default untuk kolom. Saya menemukan ini jauh lebih cepat daripada hanya menjalankan pembaruan, tetapi saya merasa ada metode yang lebih baik.

kainaw
sumber
Sejauh yang saya mengerti menambahkan kolom bukan nol baru dengan default adalah perubahan metadata hanya di Oracle. Saya ragu mereka akan mengoptimalkan kasus "perbarui semua baris dengan nilai yang sama". Apakah ini operasi yang umum untuk Anda?
Martin Smith
1
Coba saja kedua metode dan waktu mereka. Apa yang mencegah Anda melakukan ini? Lihatlah fakta bahwa Anda harus mengakhiri dengan hasil yang sama, bukan dengan hasil yang berbeda! Jika tidak, perbandingan tidak valid.
tvCa
@ tvCa Saya sudah mencoba keduanya. Jika saya hanya melakukan pembaruan, itu berjalan sekitar dua jam dan kemudian saya membunuhnya. Jika saya menjatuhkan kolom, hanya perlu beberapa detik. Menambahkan kolom tanpa nilai default (yang membatalkan kolom) hanya perlu beberapa detik. Menambahkan kolom dengan nilai default membutuhkan waktu sekitar 30 menit. Jadi, jika saya ingin, misalnya, mengatur semua nilai dalam kolom ke 'Nilai Beberapa', saya saat ini menjatuhkan dan menambahkan kolom. Saya hanya ingin tahu apakah ada cara yang lebih cepat untuk melakukannya.
kainaw
2
Apakah Anda menggunakan 11gR2? @ MartinSmith benar. Lihat di sini untuk deskripsi tentang cara menambahkan kolom baru dengan DEFAULT sebagai BUKAN NULL adalah perubahan yang jauh lebih cepat daripada menambahkannya sebagai NULL, yang akan memaksa pembaruan semua baris dalam tabel (seperti menerbitkan pernyataan UPDATE akan). Masalah yang saya lihat adalah menghapus nilai DEFAULT sesudahnya, karena peningkatan kinerja berasal dari menyimpan DEFAULT dalam kamus. Anda juga harus berurusan dengan batasan NOT NULL pada saat itu.
ansible

Jawaban:

2

Banyak tergantung pada aktivitas lain yang terjadi pada tabel ini saat Anda melakukan pembaruan massal ini. Saya harap Anda memiliki semacam lingkungan pengujian di mana Anda dapat menjalankan beberapa sampel dari apa yang ingin Anda lakukan dan mendapatkan ide tentang cara mana yang terbaik. Aku akan mencoba:

  1. Jalankan tunggal update table set column_name = blah;
  2. Buat loop plSql untuk memilih semua kunci utama dalam tabel dan loop melalui mereka, updating the column=blahdan melakukan setiap pembaruan X (mungkin 10.000). Anda dapat memparalelkan kode ini dengan menyalinnya dan membuatnya menyalin bagian terpisah dari kunci Utama.

Kami memiliki masalah yang sangat mirip dengan tabel yang sangat aktif digunakan dalam sistem OLTP dan kami dapat memparalelkannya 5x dan berlari tanpa dampak penguncian pengguna pada tabel baris 100+ MM yang dilakukan setiap 10.000. Anda tidak mengatakan bagaimana Besar meja Anda atau aplikasi apa yang sedang Anda jalankan, tetapi solusi semacam ini mungkin cocok untuk Anda.

Pete Hagerty
sumber
0

Untuk puasa UPDATE, pastikan Anda tidak memiliki pemicu yang diaktifkan.

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

ALTER TABLE mytable DISABLE ALL TRIGGERS;

Pastikan untuk hanya mengaktifkan kembali yang Anda inginkan setelah selesai.

ALTER TRIGGER mytrigger ENABLE;

Anda mungkin juga mengalami overhead pemeliharaan indeks. Cobalah membangun kembali indeks Anda secara terpisah. Untuk melakukan itu, jawaban di sini dengan pappes harus membantu: /programming/129046/disable-and-later-enable-all-table-indexes-in-oracle

Saya mengulangi jawaban pappes di sini untuk referensi. (Perhatikan bahwa perintah SPOOL ini membuat asumsi tentang platform dan lingkungan Anda.)

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

Apakah mengimpor ...

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

hapus indeks. perbarui kolom. kembalikan indeks kembali. tetapi jika kolom berisi satu dan nilai yang sama untuk semua baris, Anda dapat menjatuhkan indeks.

tatskie
sumber
-2

Jika Anda tidak memiliki batasan ruang, Anda bisa membuat tabel baru, sama seperti tabel Anda dengan kolom baru Anda ditambahkan ke tabel itu dan menghapus tabel lama:

create new_table as
select old_table.*, (with or without default_Value) as new_column
from old_table;
E_Salamon
sumber
1
Akankah ini lebih efisien? Mengapa? Dan bagaimana jika ada FK yang merujuk tabel yang ada?
ypercubeᵀᴹ
ya, Anda dapat mencobanya di tabel sampel lain dan lihat hasilnya sendiri. Jika ada FK, saya tidak tahu persis tetapi Anda dapat menonaktifkan dan mengaktifkannya jika efisien.
E_Salamon
-3

Coba beberapa pembaruan / komit urutan. Memasukkan / Memutakhirkan / Menghapus terlalu banyak baris tanpa komit mengarah ke beban IO yang berat. Ini dapat dioptimalkan dengan cukup mengetahui ukuran blok dan merekam ukuran dan barang-barang.

Untuk menghapus seluruh data pada sebuah tabel, truncate table xlebih baik daripada delete from x. Juga membersihkan membuat beban kerja proses lain.

Sunting: Anda dapat menggunakan inmemoryopsi, memuat tabel dalam memori dalam format berbentuk kolom dan kemudian melakukan pembaruan. itu benar-benar tergantung pada hubungan dan struktur DB Anda. Lihat artikel ini .

Licik
sumber
3
Mereka ingin memperbarui satu kolom dari tabel. Saya tidak melihat bagaimana truncateatau deleteakan membantu.
ypercubeᵀᴹ
@ ypercube Saya baru saja menjelaskan bagaimana beberapa manipulasi data tanpa komit mengarah ke beban IO yang tidak diinginkan; baik pembaruan atau OLTP lainnya.
Licik
3
Bisakah Anda jelaskan seberapa sering komit mengurangi I / O? Bukankah mereka meningkatkan I / O karena pos pemeriksaan?
mustaccio
3
Penggunaan terminologi non-konvensional Anda ("tx journal", "flushes your session") agak membingungkan. Apakah Anda menggunakan beberapa transaksi pendek atau satu transaksi besar, total volume catatan redo yang dihasilkan akan sama. Operasi I / O hanya terjadi ketika buffer log redo ditulis ke disk (meninggalkan sendiri pos pemeriksaan cache buffer untuk saat ini), yang terjadi saat komit atau ketika buffer ulang hampir penuh. Selanjutnya, jika Anda sering melakukan Anda menyebabkan I / O tambahan, jadi saya bertanya-tanya bagaimana itu dapat mengurangi I / O.
mustaccio
4
Anda mungkin ingin membaca apa yang dikatakan Tom Kyte tentang "sering melakukan": asktom.oracle.com/pls/apex/… " salah, salah, salah. Sangat salah .... Sangat sangat sangat salah "
a_horse_with_no_name