มีอะไรดีไปกว่าการเปลี่ยนแปลงตาราง: DELETE และ INSERT ทุกครั้งหรือมีการอัพเดทอยู่


27

ฉันกำลังทำโปรเจ็กต์ที่ต้องเปลี่ยนระเบียนประมาณ 36K ในหนึ่งตารางทุกวัน ฉันสงสัยว่าอะไรจะทำงานได้ดีกว่า:

  1. ลบแถวและแทรกแถวใหม่หรือ
  2. อัปเดตแถวที่มีอยู่แล้ว

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

นี่จะเป็นการให้บริการทุกคืนและฉันไม่ต้องการปรับปรุงความเร็วของกระบวนการเอง ฉันกังวลมากขึ้นเกี่ยวกับประสิทธิภาพของการสืบค้นเทียบกับตารางนี้โดยทั่วไปซึ่งฉันมี 89 ล้านบันทึกแล้วและกระบวนการคืนนี้จะส่งผลกระทบต่อมันอย่างไร

ฉันควรลบ / แทรกบันทึกหรือฉันควรปรับปรุงรายการที่มีอยู่ (หากเป็นไปได้) สำหรับกระบวนการทุกคืน?


ฉันเชื่อว่าคุณควรให้รายละเอียดเพิ่มเติมเกี่ยวกับตารางของคุณเนื่องจากฉันเดาว่ามันจะขึ้นอยู่กับการมีอยู่ของดัชนีในฟิลด์
SRKX

คำตอบ:


9

ขึ้นอยู่กับปริมาณข้อมูลที่เปลี่ยนแปลง สมมติว่าตารางนี้มี 20 คอลัมน์ และคุณยังมี 5 ดัชนี - แต่ละอันต่างกัน คอลัมน์.

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


ในการวิจัยเพิ่มเติมฉันพบว่าความคิดเห็นข้างต้นโดยฉันเป็นประเภทที่ซ้ำซ้อนเนื่องจาก SQL Server ภายในมีกลไกที่แยกจากกัน 2 แบบสำหรับการดำเนินการ UPDATE - "การอัปเดตแบบแทนที่" (เช่นโดยการเปลี่ยนค่าคอลัมน์เป็นใหม่ในแถวเดิม) หรือเป็น "การอัปเดตแบบไม่เข้าแทนที่" (DELETE ตามด้วย INSERT)

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

ตัวอย่างเช่น: หากคุณมีดัชนีคลัสเตอร์ในชื่อและคุณมีชื่อ: สามารถเบเกอร์, ชาร์ลีตอนนี้คุณต้องการอัปเดตเบเกอร์เป็นเบกเกอร์ ไม่ต้องย้ายแถว ดังนั้นสิ่งนี้สามารถใช้แทน ในขณะที่หากคุณต้องอัปเดตสามารถไปที่ Kumar แถวนั้นจะต้องเปลี่ยน (แม้ว่าพวกเขาจะอยู่ในหน้าเดียวกัน) ในกรณีนี้ SQL Server จะทำการลบตามด้วย INSERT

จากการพิจารณาข้างต้นฉันขอแนะนำให้คุณทำการอัพเดทปกติและให้ SQL Server หาวิธีที่ดีที่สุดในการทำภายใน

. สำหรับรายละเอียดเพิ่มเติมเกี่ยวกับ "UPDATE" internals หรือว่าเรื่องใด ๆ ที่เกี่ยวข้องกับเซิร์ฟเวอร์ SQL internals ตรวจสอบเคเลนเดลานีย์, พอล Randal ของ, et al หนังสือ - SQL Server 2008 Internals


8

คุณตรวจสอบคำสั่งMERGEใน SQL 2008 แล้วหรือยัง? นี่คือตัวอย่างพื้นฐาน:

  merge YourBigTable ybt
  using (select distinct (RecordID) from YourOtherTable) yot
     on yot.Recordid = YBT.RecordID
  when NOT matched by target
  then  insert (RecordID)
        values (yot.DeviceID) ;

นี่คือคำสั่ง "UPSERT" โดยทั่วไป อัปเดตหากมีอยู่ให้ใส่ถ้าไม่มี คำสั่งที่เร็วและเจ๋งมาก


1
มันไม่เร็วกว่าการอัพเดทกลไกแบบเดียวกันภายใต้ประทุน
Mark Storey-Smith

มันเร็วกว่าการอัปเดตจากนั้นจึงแทรกสิ่งที่ไม่ได้มีอยู่
datagod

2
หากคุณรู้ว่าเป็นกรณีนี้ให้พิสูจน์ :)
Mark Storey-Smith

4

แต่ฉันเองตรวจสอบการลบและการแทรกการปรับปรุง vs บนตารางที่มีเรกคอร์ด 30 ล้าน (3crore) ตารางนี้มีคีย์ผสมที่ไม่ซ้ำกันหนึ่งคลัสเตอร์และ 3 คีย์ที่ไม่คลัสเตอร์ สำหรับการลบและแทรกใช้เวลา 9 นาที สำหรับการอัปเดตใช้เวลา 55 นาที มีคอลัมน์เดียวเท่านั้นที่ได้รับการปรับปรุงในแต่ละแถว

ดังนั้นฉันขอให้คุณไม่เดา สมการจะเปลี่ยนไปเมื่อจัดการกับตารางขนาดใหญ่ที่มีหลายคอลัมน์และมีข้อมูลจำนวนมาก


ฉันได้ตีกรณีนี้แล้ว แต่ก็ค้นพบว่าบางครั้งมันเป็นไปได้ที่จะเพิ่มประสิทธิภาพการรวมขนาดใหญ่โดยการเพิ่มตัวบ่งชี้ (temp หรือระดับการอนุญาต) ไปยังแหล่งที่มาหรือเป้าหมายคำแนะนำหรือการตั้งค่าเป้าหมายย่อย
crokusek

3

การอัปเดตไม่เร็วเท่านี้ เคล็ดลับคือการบรรลุการแทรกที่รวดเร็วคือการปิดการใช้งานดัชนีขณะที่ข้อมูลกำลังถูกแทรก

พิจารณาใช้สิ่งนี้:

-- disable indexes
ALTER INDEX [index_name] ON dbo.import_table DISABLE
-- ... disable more indexes

-- don't use delete if you don't care about minimal logging. truncate is faster
TRUNCATE TABLE dbo.import_table

-- just insert the new rows
INSERT dbo.import_table
SELECT
    *
FROM
    dbo.source_table

-- rebuild indexes
ALTER INDEX [index_name] ON dbo.import_table REBUILD
-- ... rebuild more indexes

ยิ่งเร็วขึ้นคือการปิดการอัพเดตสถิติอัตโนมัติในตัวเลือก db หากตารางมีการเปลี่ยนแปลงอย่างมีนัยสำคัญคุณควรเรียกใช้:

UPDATE STATISTICS dbo.import_table

หรือ

EXEC sp_updatestats

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


4
ฉันไม่เห็นด้วยว่านี่เป็นกรณีเสมอ และไม่สามารถล้างตารางในคำถามของ @ adopilot โดย TRUNCATE เนื่องจากมีระเบียน 89m และเขาต้องการอัปเดตเพียง 36k
Mark Storey-Smith

ต้องเรียนรู้ที่จะอ่านโพสต์อย่างระมัดระวังมากขึ้น! ฉันจะอัปเดตโพสต์ ... จริง ๆ แล้วฉันต้องเปลี่ยนมาก
Asken
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.