ตัวดำเนินการสปูลกระตือรือร้นมีประโยชน์สำหรับการลบนี้จากคอลัมน์ในคลัสเตอร์หรือไม่


28

ฉันกำลังทดสอบการลบข้อมูลจากดัชนี columnstore แบบคลัสเตอร์

ฉันสังเกตเห็นว่ามีตัวดำเนินการเก็บพักขนาดใหญ่ที่กระตือรือร้นในแผนการดำเนินการ:

ป้อนคำอธิบายรูปภาพที่นี่

สิ่งนี้เสร็จสมบูรณ์ด้วยคุณสมบัติดังต่อไปนี้:

  • ลบ 60 ล้านแถว
  • 1.9 GiB TempDB ใช้แล้ว
  • เวลาดำเนินการ 14 นาที
  • แผนอนุกรม
  • 1 rebind บนสปูล
  • ค่าใช้จ่ายโดยประมาณสำหรับการสแกน: 364.821

หากฉันหลอกผู้ประมาณค่าให้ดูถูกดูแคลนฉันจะได้รับแผนการที่เร็วกว่าและหลีกเลี่ยงการใช้ TempDB:

ป้อนคำอธิบายรูปภาพที่นี่

ค่าใช้จ่ายโดยประมาณของการสแกน: 56.901

(นี่เป็นแผนโดยประมาณ แต่ตัวเลขในความคิดเห็นถูกต้อง)

ที่น่าสนใจที่เก็บพักหายไปอีกครั้งถ้าฉันล้างร้านค้าเดลต้าโดยเรียกใช้ต่อไปนี้:

ALTER INDEX IX_Clustered ON Fact.RecordedMetricsDetail REORGANIZE WITH (COMPRESS_ALL_ROW_GROUPS = ON);

สปูลจะปรากฏขึ้นเฉพาะเมื่อมีจำนวนหน้ามากกว่าเกณฑ์ในร้านเดลต้า

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

SELECT  
  SUM([in_row_used_page_count]) AS in_row_used_pages,
  SUM(in_row_data_page_count) AS in_row_data_pages
FROM sys.[dm_db_partition_stats] as pstats
JOIN sys.partitions AS p
ON pstats.partition_id = p.partition_id
WHERE p.[object_id] = OBJECT_ID('Fact.RecordedMetricsDetail');

มีประโยชน์ใด ๆ ที่น่าเชื่อถือในการวนรอบในแผนแรก? ฉันต้องสมมติว่ามันมีจุดประสงค์เพื่อเป็นการเพิ่มประสิทธิภาพและไม่ใช่เพื่อการป้องกันฮาโลวีนเนื่องจากสถานะไม่สอดคล้องกัน

ฉันกำลังทดสอบสิ่งนี้ในปี 2559 CTP 3.1 แต่ฉันเห็นพฤติกรรมเดียวกันใน 2014 SP1 CU3

ผมเคยโพสต์สคริปต์ที่สร้างสคีและข้อมูลและคุณเดินผ่านแสดงให้เห็นถึงปัญหาที่เกิดขึ้นที่นี่

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


2
หากฉันลองOPTION (QUERYRULEOFF EnforceHPandAccCard)เก็บพักหายไป ฉันถือว่า HP อาจเป็น "Halloween Protection" แต่แล้วพยายามที่จะใช้แผนการที่มีUSE PLANคำใบ้ล้มเหลว (เช่นเดียวกับการพยายามที่จะใช้แผนจากOPTIMIZE FOR การแก้ปัญหามากเกินไป)
มาร์ตินสมิ ธ

ขอบคุณ @MartinSmith ความคิดอะไรAccCardจะเป็นอย่างไร ความสำคัญสูงสุดของคอลัมน์
James L

1
@ JamesLupolt ไม่ฉันไม่สามารถคิดอะไรเป็นพิเศษกับฉันได้ บางที Acc คือการสะสมหรือการเข้าถึง?
Martin Smith

คำตอบ:


22

มีประโยชน์ใด ๆ ที่น่าเชื่อถือในการวนรอบในแผนแรก?

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

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

DELETE Fact.RecordedMetricsDetail
WHERE MeasurementTime < DATEADD(day,-1,GETUTCDATE())
OPTION (RECOMPILE);

ค่าใช้จ่ายโดยประมาณสำหรับแผนนี้มีขนาดใหญ่771,734 หน่วย :

แผนเดิม

ค่าใช้จ่ายเกือบทั้งหมดที่เกี่ยวข้องกับการลบดัชนีแบบกลุ่มเนื่องจากการลบที่คาดว่าจะส่งผลใน I / O แบบสุ่มอย่างมาก นี่เป็นเพียงตรรกะทั่วไปที่ใช้กับการปรับเปลี่ยนข้อมูลทั้งหมด ตัวอย่างเช่นชุดการแก้ไขที่ไม่เรียงลำดับของดัชนี b-tree จะถือว่าส่งผลให้ I / O แบบสุ่มส่วนใหญ่มีค่าใช้จ่าย I / O สูงที่เกี่ยวข้อง

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

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

ฉันพูดถึงสิ่งนี้เนื่องจากความสามารถในการใช้การเพิ่มประสิทธิภาพนี้หมายถึงเครื่องมือเพิ่มประสิทธิภาพใช้เส้นทางรหัสที่ไม่ได้พิจารณาถึงประโยชน์ที่อาจเกิดขึ้นจากการเรียงลำดับอย่างชัดเจนเพื่อลดต้นทุนของการสุ่ม I / O ในกรณีที่ตารางเป็น b-tree สิ่งนี้สมเหตุสมผลเนื่องจากโครงสร้างได้รับคำสั่งโดยเนื้อแท้ดังนั้นการแบ่งปันชุดข้อมูลจะให้ประโยชน์ที่เป็นไปได้ทั้งหมดโดยอัตโนมัติ

ผลลัพธ์ที่สำคัญคือตรรกะการคิดต้นทุนสำหรับผู้ดำเนินการอัพเดทไม่ได้คำนึงถึงประโยชน์ในการสั่งซื้อนี้ (การส่งเสริม I / O ตามลำดับหรือการปรับให้เหมาะสมอื่น ๆ ) โดยที่วัตถุต้นแบบคือที่เก็บคอลัมน์ นี่เป็นเพราะการปรับเปลี่ยนการจัดเก็บคอลัมน์จะไม่ดำเนินการในสถานที่; พวกเขาใช้ร้านเดลต้า รูปแบบค่าใช้จ่ายจึงสะท้อนให้เห็นถึงความแตกต่างระหว่างการอัพเดตชุด - rowset ที่ใช้ร่วมกันบน b-trees เทียบกับที่เก็บคอลัมน์

อย่างไรก็ตามในกรณีพิเศษของคอลัมน์ที่แบ่งพาร์ติชัน (มาก!) อาจมีประโยชน์ในการสั่งซื้อที่สงวนไว้ในการดำเนินการอัปเดตทั้งหมดไปยังพาร์ติชันหนึ่งก่อนที่จะย้ายไปยังพาร์ติชันถัดไปอาจยังคงได้เปรียบจากมุมมอง I / O .

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

DELETE Fact.RecordedMetricsDetail
WHERE MeasurementTime < DATEADD(day,-1,GETUTCDATE())
OPTION (RECOMPILE, QUERYTRACEON 2332);

ค่าใช้จ่ายโดยประมาณสำหรับแผนนี้ต่ำกว่ามากมากที่52.5174หน่วย:

DMLRequestSort = แผนการที่แท้จริง

การลดต้นทุนนี้เป็นผลมาจากต้นทุน I / O โดยประมาณที่ต่ำกว่าในการอัพเดท Spool ที่แนะนำไม่มีฟังก์ชั่นที่มีประโยชน์ยกเว้นว่ามันจะสามารถรับประกันเอาต์พุตในลำดับของพาร์ติชั่นได้ตามที่ต้องการโดยการอัพเดทด้วยDMLRequestSort = true(การสแกนอนุกรมของดัชนีที่เก็บคอลัมน์ไม่สามารถรับประกันได้) ค่าใช้จ่ายของสปูลนั้นถือว่าอยู่ในระดับค่อนข้างต่ำโดยเฉพาะอย่างยิ่งเมื่อเทียบกับการลดต้นทุน (ที่อาจไม่สมจริง) ในการอัปเดต

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

มีวิธีอื่นในการรับแผนต้นทุนต่ำสำหรับการสืบค้นนี้โดยไม่ จำกัด การประเมินความสำคัญของ cardinality การประเมินที่ต่ำเพียงพอเพื่อหลีกเลี่ยง Spool อาจส่งผลให้ DMLRequestSort เป็นเท็จทำให้มีค่าใช้จ่ายตามแผนโดยประมาณสูงมากเนื่องจาก I / O แบบสุ่มที่คาดไว้ อีกทางเลือกหนึ่งคือใช้การตั้งค่าสถานะการสืบค้นกลับ 8649 (แผนขนาน) ร่วมกับ 2332 (DMLRequestSort = true):

DELETE Fact.RecordedMetricsDetail
WHERE MeasurementTime < DATEADD(day,-1,GETUTCDATE())
OPTION (RECOMPILE, QUERYTRACEON 2332, QUERYTRACEON 8649);

สิ่งนี้ส่งผลในแผนที่ใช้การสแกนแบบขนานในแต่ละแบทช์พาร์ติชันและการแลกเปลี่ยนเพื่อรักษา (ผสาน) การรวบรวม Gather Streams:

สั่งลบ

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

การรวมคุณสมบัติที่ค่อนข้างใหม่โดยเฉพาะอย่างยิ่งใกล้ขีด จำกัด ของพวกเขาเป็นวิธีที่ดีในการรับแผนปฏิบัติการที่ไม่ดี ความลึกของการสนับสนุนเครื่องมือเพิ่มประสิทธิภาพมีแนวโน้มที่จะดีขึ้นเมื่อเวลาผ่านไป แต่การใช้งานพาร์ทิชันคอลัมน์จำนวน 15,000 พาร์ติชั่นมักจะหมายถึง

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