อัปเดตแถวทั้งหมด


12

ฉันต้องการทราบวิธีที่มีประสิทธิภาพที่สุดในการอัปเดตทุกแถวในตาราง Oracle ที่มีขนาดใหญ่มากสำหรับคอลัมน์เดียว ตัวอย่างเช่น:

update mytable set mycolumn=null;

หรือ:

update mytable set mycolumn=42;

ความรู้ของฉันอาจจะเหม็นอับ สิ่งที่ฉันทำคือการปรับเปลี่ยนตารางเพื่อวางคอลัมน์ จากนั้นฉันเปลี่ยนตารางเพื่อเพิ่มคอลัมน์ด้วยค่าเริ่มต้นของค่าใหม่ที่ฉันต้องการใช้ จากนั้นฉันจะแก้ไขตารางเพื่อลบค่าเริ่มต้นสำหรับคอลัมน์ ฉันพบว่าสิ่งนี้เร็วกว่าแค่เรียกใช้การอัปเดต แต่ฉันรู้สึกว่ามีวิธีที่ดีกว่า


เท่าที่ฉันเข้าใจมันเพิ่มคอลัมน์ใหม่ไม่เป็นโมฆะกับค่าเริ่มต้นคือการเปลี่ยนแปลงข้อมูลเมตาใน Oracle เท่านั้น ฉันสงสัยว่าพวกเขาจะเพิ่มประสิทธิภาพกรณี "อัปเดตทุกแถวเป็นค่าเดียวกัน" นี่เป็นการดำเนินการทั่วไปสำหรับคุณหรือไม่
Martin Smith

1
เพียงลองทั้งวิธีการและเวลา คุณป้องกันไม่ให้ทำสิ่งนี้ จงดูความจริงที่ว่าคุณจะต้องจบด้วยผลลัพธ์เดียวกันไม่ใช่ด้วยผลที่ต่างออกไป! มิฉะนั้นการเปรียบเทียบไม่ถูกต้อง
tvCa

@tvCa ฉันลองทั้งสองวิธีแล้ว ถ้าฉันเพิ่งอัพเดทมันจะใช้เวลาประมาณสองชั่วโมงแล้วฉันจะฆ่ามัน ถ้าฉันวางคอลัมน์จะใช้เวลาเพียงไม่กี่วินาที การเพิ่มคอลัมน์โดยไม่มีค่าเริ่มต้น (ซึ่งเป็นโมฆะคอลัมน์) จะใช้เวลาเพียงไม่กี่วินาที การเพิ่มคอลัมน์ที่มีค่าเริ่มต้นใช้เวลาประมาณ 30 นาที ตัวอย่างเช่นถ้าฉันต้องการตั้งค่าทั้งหมดในคอลัมน์เป็น 'บางค่า' ตอนนี้ฉันวางแล้วเพิ่มคอลัมน์ ฉันแค่อยากรู้ว่ามีวิธีที่เร็วกว่าที่จะทำหรือไม่
kainaw

2
คุณใช้ 11gR2 หรือไม่ @MartinSmith ถูกต้อง ดูที่นี่สำหรับคำอธิบายเกี่ยวกับวิธีเพิ่มคอลัมน์ใหม่ด้วยค่าเริ่มต้นเนื่องจาก NOT NULL เป็นการเปลี่ยนแปลงที่เร็วกว่าการเพิ่มเป็น NULL ซึ่งจะบังคับให้มีการอัปเดตแถวทั้งหมดในตาราง (เช่นเดียวกับการออกคำสั่ง UPDATE) ปัญหาที่ฉันเห็นคือการลบค่าเริ่มต้นหลังจากนั้นเนื่องจากการเพิ่มประสิทธิภาพมาจากการจัดเก็บ DEFAULT ในพจนานุกรม คุณจะต้องจัดการกับข้อ จำกัด NOT NULL ณ จุดนั้น
ansible

คำตอบ:


2

หลายอย่างขึ้นอยู่กับกิจกรรมอื่น ๆ ที่เกิดขึ้นกับตารางนี้ในขณะที่คุณทำการอัปเดตจำนวนมาก ฉันหวังว่าคุณจะมีสภาพแวดล้อมการทดสอบบางประเภทที่คุณสามารถเรียกใช้ตัวอย่างบางส่วนของสิ่งที่คุณต้องการจะทำและได้รับแนวคิดว่าวิธีไหนดีที่สุด ฉันจะพยายาม:

  1. เรียกเดี่ยวupdate table set column_name = blah;
  2. สร้างการวนซ้ำ plSql เพื่อเลือกคีย์หลักทั้งหมดในตารางและวนผ่านมันupdating the column=blahและยอมรับการอัพเดท X ทุกครั้ง (อาจ 10,000) คุณสามารถทำให้ขนานรหัสนี้โดยการคัดลอกและทำสำเนาทำส่วนแยกต่างหากของคีย์หลัก

เรามีปัญหาที่คล้ายกันมากกับตารางที่ใช้กันอย่างแพร่หลายในระบบ OLTP และเราสามารถทำให้มันขนานกันได้ 5 เท่าและวิ่งโดยไม่มีผลกระทบต่อผู้ใช้ในการล็อกบนตารางแถว 100+ MM ที่กระทำทุก 10,000 คุณไม่ได้พูดว่าอย่างไร ตารางของคุณมีขนาดใหญ่หรือแอปพลิเคชันของคุณกำลังทำงานอยู่ แต่โซลูชันประเภทนี้อาจเหมาะกับคุณ


0

เพื่อความรวดเร็วUPDATEตรวจสอบว่าคุณไม่มีทริกเกอร์ใด ๆ ที่กำลังถูกยิง

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

ALTER TABLE mytable DISABLE ALL TRIGGERS;

ให้แน่ใจว่าได้เปิดใช้งานสิ่งที่คุณต้องการอีกครั้งเมื่อคุณทำเสร็จแล้ว

ALTER TRIGGER mytrigger ENABLE;

คุณอาจพบปัญหาค่าใช้จ่ายในการบำรุงรักษาดัชนี ลองสร้างดัชนีของคุณใหม่แยกกัน หากต้องการทำเช่นนั้นคำตอบที่นี่โดย pappes ควรเป็นประโยชน์: /programming/129046/disable-and-later-enable-all-table-indexes-in-oracle

ฉันกำลังทำซ้ำคำตอบ pappes 'ที่นี่เพื่อการอ้างอิง (โปรดทราบว่าคำสั่ง SPOOL นี้สร้างสมมติฐานเกี่ยวกับแพลตฟอร์มและสภาพแวดล้อมของคุณ)

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

ทำการนำเข้า ...

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

-1

ลบดัชนี อัปเดตคอลัมน์ คืนดัชนีกลับ แต่ถ้าคอลัมน์นั้นมีค่าเดียวกับทุกแถวคุณสามารถดร็อปดัชนีได้


-2

หากคุณไม่มีข้อ จำกัด ด้านพื้นที่คุณสามารถสร้างตารางใหม่เช่นเดียวกับตารางที่เพิ่มคอลัมน์ใหม่ลงในตารางนั้นและลบตารางเก่า:

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

1
สิ่งนี้จะมีประสิทธิภาพมากขึ้นหรือไม่ ทำไม? และถ้ามี FK ที่อ้างอิงตารางที่มีอยู่ล่ะ
ypercubeᵀᴹ

ใช่คุณสามารถลองในตารางตัวอย่างอื่นและดูผลลัพธ์ด้วยตัวคุณเอง หากมี FK ฉันไม่ทราบแน่ชัด แต่คุณสามารถปิดใช้งานและเปิดใช้งานได้หากมันมีประสิทธิภาพ
E_Salamon

-3

ลองอัปเดต / ส่งหลายชุด การแทรก / การอัปเดต / การลบแถวมากเกินไปโดยไม่มีการคอมมิตทำให้เกิดการโหลด IO อย่างหนัก มันสามารถปรับให้เหมาะสมพอสมควรเมื่อรู้ขนาดบล็อกและขนาดบันทึกและสิ่งต่าง ๆ

สำหรับการลบข้อมูลทั้งหมดบนโต๊ะจะดีกว่าtruncate table x delete from xนอกจากนี้การกวาดล้างทำให้ภาระงานกระบวนการอื่น

แก้ไข:คุณสามารถใช้inmemoryตัวเลือกโหลดตารางในหน่วยความจำในรูปแบบเรียงเป็นแนวแล้วทำการอัพเดต มันขึ้นอยู่กับความสัมพันธ์และโครงสร้างของฐานข้อมูลของคุณ ดูบทความนี้


3
พวกเขาต้องการอัปเดตหนึ่งคอลัมน์ของตาราง ผมไม่เห็นว่าtruncateหรือdeleteจะเป็นความช่วยเหลือใด ๆ
ypercubeᵀᴹ

@ypercube ฉันเพิ่งอธิบายว่าการจัดการข้อมูลหลายอย่างโดยไม่ส่งข้อมูลนำไปสู่การโหลด IO ที่ไม่พึงประสงค์; อาจอัปเดตหรือ OLTP อื่น ๆ
ไหวพริบ

3
คุณช่วยอธิบายว่าการลด I / O ได้บ่อยแค่ไหน? พวกเขาจะไม่เพิ่ม I / O เนื่องจากจุดตรวจใช่หรือไม่
mustaccio

3
การใช้คำศัพท์ที่ไม่ธรรมดา ("วารสาร tx", "ล้างเซสชั่นของคุณ") ทำให้เกิดความสับสนเล็กน้อย ไม่ว่าคุณจะใช้ธุรกรรมระยะสั้นหลายรายการหรือธุรกรรมขนาดใหญ่หนึ่งรายการปริมาณการทำซ้ำเรคคอร์ดทั้งหมดจะเหมือนกัน การดำเนินการ I / O จะเกิดขึ้นเฉพาะเมื่อมีการเขียนบันทึกบัฟเฟอร์การทำซ้ำไปยังดิสก์ (ปล่อยให้จุดตรวจสอบแคชบัฟเฟอร์เพียงอย่างเดียวในตอนนี้) ซึ่งเกิดขึ้นเมื่อส่งมอบหรือเมื่อบัฟเฟอร์การทำซ้ำเกือบเต็ม ต่อจากนั้นหากคุณกระทำบ่อยครั้งคุณทำให้ I / O เพิ่มเติมดังนั้นฉันสงสัยว่าจะลด I / O ได้อย่างไร
mustaccio

4
คุณอาจต้องการที่จะอ่านสิ่งที่ทอม Kyte ได้กล่าวเกี่ยวกับ "กระทำบ่อย": asktom.oracle.com/pls/apex/... " ผิดผิดผิดผิดแล้ว .... ดังนั้นมากผิดมาก. "
a_horse_with_no_name
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.