SQL“ ตารางที่ว่าง” ช้าลงหลังจากลบระเบียนทั้งหมด (12 ล้าน)?


27

ฉันมีอินสแตนซ์ SQL Server 2008 ที่มีคอลัมน์ประมาณ 150 คอลัมน์ ก่อนหน้านี้ฉันได้เติมข้อมูลตารางนี้ด้วยรายการประมาณ 12 ล้านรายการ แต่หลังจากนั้นจึงล้างตารางเพื่อเตรียมชุดข้อมูลใหม่

อย่างไรก็ตามคำสั่งที่เคยวิ่งทันทีบนโต๊ะว่างเช่น count(*)และselect top 1000ในSQL Management Studioตอนนี้พามหายุคให้ทำงาน

SELECT COUNT(*) FROM TABLE_NAME 

ใช้เวลามากกว่า 11 นาทีเพื่อส่งคืน 0 และSELECT TOP 1000ใช้เวลาเกือบ 10 นาทีเพื่อส่งคืนตารางเปล่า

ฉันยังสังเกตเห็นว่าพื้นที่ว่างบนฮาร์ดไดรฟ์ของฉันได้หายไปอย่างแท้จริง (ลดลงจากประมาณ 100G ถึง 20G) สิ่งเดียวที่เกิดขึ้นระหว่างคือแบบสอบถามเดียวที่ฉันวิ่ง:

DELETE FROM TABLE_NAME

เกิดอะไรขึ้นในโลกนี้!


5
ฐานข้อมูลของคุณใช้รูปแบบการกู้คืนใด หากเป็น "เต็ม" อินสแตนซ์ SQL ของคุณจะเก็บบันทึกการลบเหล่านั้นทั้งหมดซึ่งอาจเป็นที่ว่างของคุณไป หากการกู้คืนเต็มความต้องการของผมแนะนำให้ใช้แทนTRUNCATE TABLE DELETE FROM
Tullo_x86

2
150 คอลัมน์ ตารางนั้นอาจใหญ่เกินไป - ทูเปิลส่วนใหญ่ควรเล็กกว่ามาก อย่างไรก็ตามเป็นไปไม่ได้ที่จะพูดโดยไม่มีบริบท
Clockwork-Muse

คำตอบ:


42

คุณได้รับการบอกเล่าเกี่ยวกับสาเหตุ TRUNCATEจะเร็วกว่า / ดีกว่า / เซ็กซี่กว่าDELETEแต่ก็ยังมีคำถามจากที่อยู่:

ทำไมSELECTช้ากว่าDELETE เสร็จ ?

นั่นเป็นเพราะDELETEมีเพียงโกสต์แถว ตารางมีขนาดใหญ่เท่ากับเมื่อมีแถว 12 ล้านตารางเมตรแม้ว่าจะไม่มีเลยก็ตาม หากต้องการนับจำนวนแถว (0) จะต้องใช้เวลามากพอที่จะนับแถว 12M ในเวลาที่ขั้นตอนการล้างข้อมูลผีจะเก็บรวบรวมระเบียนที่โกสต์เหล่านี้และหน้าการจัดสรรคืนที่มีเพียงผีและการเลือกของคุณจะเร็วขึ้น แต่ตอนนี้ถ้าคุณตรวจสอบSkipped Ghosted Records/secใน perfmon SELECT COUNT(*)อาจจะพุ่งสูงขึ้นในช่วง ALTER TABLE ... REBUILDนอกจากนี้คุณยังสามารถเพิ่มความเร็วในการสร้างสิ่งโดยตาราง:

TRUNCATE จะดูแลปัญหานี้ด้วยเหมือนกันเพราะไม่มีผีอยู่ข้างหลัง

ดูเพิ่มเติมภายในเครื่องยนต์การเก็บรักษา: ทำความสะอาดผีในเชิงลึก


13

DELETEคำสั่งจะลบแถวออกจากตารางหนึ่งทีละรายการบันทึกแต่ละแถวในtransaction logและรักษาlog sequence number (LSN)ข้อมูล เมื่อคุณกล่าวถึงตารางของคุณมีข้อมูลจำนวนมาก (12 ล้านบันทึก) หลังจากที่ลบฮาร์ดดิสก์ของคุณออกจากพื้นที่แล้วให้ตรวจสอบขนาดของไฟล์บันทึกฐานข้อมูลของคุณ มันอาจจะเติบโตขึ้นส่วนใหญ่

วิธีที่ดีกว่านั้นก็คือ:

TRUNCATE TABLE_NAME

2
+1 เหมือนกันทุกประการกับ Oracle DB หากคุณใช้คำสั่งที่ก่อให้เกิดการบันทึกบันทึกมันจะชะลอตัวลงฐานข้อมูลในช่วงเวลา
Petro Semeniuk

@ PetroSemeniuk จากสิ่งที่ฉันจำได้บน Oracle ให้ลบเครื่องหมาย highwater เพียงอย่างเดียวการตัดปลายจะรีเซ็ตเครื่องหมาย highwater ฉันเชื่อว่าการดำเนินการใด ๆ ที่ต้องใช้การสแกนแบบเต็มจะสแกนบล็อกจนกว่าจะมีเครื่องหมายน้ำสูง ดังนั้นการลบอาจช่วยการดำเนินการทำดัชนี แต่ไม่สแกน TRUNCATE เป็นการดำเนินการที่เหมาะสม
Glenn

3

(แต่เดิมนี่เป็นความเห็นต่อคำตอบของ @ DaveE แต่ฉันได้ใส่ไว้ในคำตอบของตัวเองเพราะมันยาว)

TRUNCATE คือการดำเนินการเข้าสู่ระบบ มันจะต้องเป็นอย่างอื่นมันไม่ได้เป็นไปตามข้อกำหนดของกรด อย่างไรก็ตามความแตกต่างระหว่างTRUNCATEและDELETE:

  • การใช้พื้นที่บันทึก: TRUNCATEบันทึกเฉพาะหน้า / ส่วนขยาย * อิสระDELETEบันทึกแต่ละแถว
  • การใช้งานการล็อก: TRUNCATEโดยทั่วไปจะใช้การล็อกน้อยลงเนื่องจากใช้การล็อกตารางและการล็อกหน้าซึ่งต่างจากการDELETEใช้การล็อกแถว **
  • IDENTITYsequences: TRUNCATEรีเซ็ตลำดับตัวตนบนตารางหากมี

(* ขอบเขต = 8 หน้า.) TRUNCATEจะบันทึก / ลบส่วนขยายหากอยู่ในตารางนั้นมิฉะนั้นจะบันทึก / ลบหน้าจากส่วนต่างผสม

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

ดังนั้น (กลับไปที่คำถามเดิม) TRUNCATE TABLEจะสรุปได้ดีกว่าDELETE FROM TABLEถ้าคุณกำลังล้างตารางออก แต่ต้องการรักษาโครงสร้างไว้ (NB:TRUNCATEไม่สามารถใช้บนโต๊ะที่อ้างอิงโดยคีย์ต่างประเทศจากตารางอื่น)

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

ในที่สุดสิ่งอื่นที่ต้องระวัง - ตารางสถิติ เรียกใช้UPDATE STATISTICS <TABLENAME>' afterTRUNCATE /DELETE` เพื่อให้เครื่องมือเพิ่มประสิทธิภาพการสืบค้นไม่ได้รับสถิติเพิ่มขึ้น


2

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

และใช้ TRUNCATE TABLE เมื่อคุณต้องการทำสิ่งนี้ในอนาคต

แก้ไข: คำสั่งของฉันเกี่ยวกับ TRUNCATE ไม่ได้ถูกบันทึกอยู่ในข้อผิดพลาด ลบออก

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