ฉันมีคำสั่ง SQL UPDATE พร้อมประโยค "TOP (X)" และแถวที่ฉันอัปเดตค่ามีประมาณ 4 พันล้านแถว เมื่อฉันใช้ "TOP (10)" ฉันจะได้รับแผนการดำเนินการหนึ่งแผนซึ่งจะดำเนินการเกือบจะทันที แต่เมื่อฉันใช้ "TOP (50)" หรือใหญ่กว่าแบบสอบถามจะไม่เสร็จสิ้น (อย่างน้อยไม่ใช่ในขณะที่ฉันรอ) มันใช้แผนการดำเนินการที่แตกต่างอย่างสิ้นเชิง เคียวรีขนาดเล็กใช้แผนอย่างง่ายมากที่มีคู่ของการค้นหาดัชนีและการเข้าร่วมลูปที่ซ้อนกันซึ่งแบบสอบถามเดียวกันที่แน่นอน (มีจำนวนแถวที่แตกต่างกันในส่วนคำสั่งย่อยด้านบนของคำสั่ง UPDATE) ใช้แผนที่เกี่ยวข้องกับการค้นหาดัชนีสองรายการ สปูลของตารางการขนานและความซับซ้อนอื่น ๆ
ฉันใช้ "OPTION (ใช้แผน ... )" เพื่อบังคับให้ใช้แผนการดำเนินการที่สร้างโดยเคียวรีขนาดเล็ก - เมื่อฉันทำสิ่งนี้ฉันสามารถอัปเดตได้มากถึง 100,000 แถวในไม่กี่วินาที ฉันรู้ว่าแผนการสืบค้นเป็นสิ่งที่ดี แต่ SQL Server จะเลือกแผนนั้นด้วยตัวเองเมื่อมีจำนวนแถวที่เกี่ยวข้องน้อย - จำนวนแถวที่มีขนาดใหญ่พอสมควรในการอัปเดตของฉันจะส่งผลให้แผนย่อยดีที่สุด
ฉันคิดว่าการขนานกันนั้นอาจจะเป็นความผิดดังนั้นฉันจึงตั้งMAXDOP 1
คำถาม แต่ไม่มีผลใด ๆ - ขั้นตอนนั้นหายไป แต่ตัวเลือก / ประสิทธิภาพไม่ดี sp_updatestats
เช้านี้ฉันก็วิ่งไปด้วยเพื่อให้แน่ใจว่าไม่ใช่สาเหตุ
ฉันได้แนบแผนปฏิบัติการสองแผน - แผนที่สั้นกว่าก็เป็นแผนที่เร็วกว่าด้วย นอกจากนี้ต่อไปนี้เป็นคำถามที่ถาม (น่าสังเกตว่า SELECT ที่ฉันรวมไว้ดูเหมือนว่าจะรวดเร็วในกรณีของจำนวนแถวทั้งเล็กและใหญ่):
update top (10000) FactSubscriberUsage3
set AccountID = sma.CustomerID
--select top 50 f.AccountID, sma.CustomerID
from FactSubscriberUsage3 f
join dimTime t
on f.TimeID = t.TimeID
join #mac sma
on f.macid = sma.macid
and t.TimeValue between sma.StartDate and sma.enddate
where f.AccountID = 0 --There's a filtered index on the table for this
มีอะไรที่ชัดเจนทั้งในวิธีที่ฉันตั้งค่าคิวรีของฉันหรือในแผนการดำเนินการโดยมีเงื่อนไขว่าจะให้ตัวเลือกที่ไม่ถูกต้องกับเอ็นจิ้นการสืบค้น หากจำเป็นฉันสามารถรวมคำจำกัดความของตารางที่เกี่ยวข้องและดัชนีที่กำหนดไว้
สำหรับผู้ที่ขอวัตถุฐานข้อมูลรุ่นสถิติเท่านั้น: ฉันไม่เคยรู้เลยว่าคุณสามารถทำได้ แต่มันก็สมเหตุสมผลดี! ฉันพยายามสร้างสคริปต์สำหรับฐานข้อมูลสถิติอย่างเดียวเพื่อให้ผู้อื่นสามารถทดสอบแผนการดำเนินการสำหรับตัวเอง แต่ฉันสามารถสร้างสถิติ / ฮิสโตแกรมในดัชนีตัวกรองของฉัน (ดูเหมือนข้อผิดพลาดทางไวยากรณ์ในสคริปต์ดูเหมือน) ดังนั้นฉัน ออกจากโชคที่นั่น ฉันลองลบตัวกรองออกและแผนการสืบค้นใกล้เคียงกัน แต่ไม่เหมือนกันทุกประการและฉันไม่ต้องการส่งใครไล่ล่าห่าน
อัปเดตและแผนการดำเนินการที่สมบูรณ์ยิ่งขึ้น: ก่อนอื่นPlan Explorer ของ SQL Sentryเป็นเครื่องมือที่เหลือเชื่อ ฉันไม่รู้ด้วยซ้ำจนกระทั่งดูคำถามแผนแบบสอบถามอื่น ๆ ในไซต์นี้และมันก็ค่อนข้างพูดได้นิดหน่อยว่าแบบสอบถามของฉันทำงานอย่างไร แม้ว่าฉันจะไม่แน่ใจว่าจะจัดการกับปัญหาได้อย่างไร แต่พวกเขาทำให้มันชัดเจนว่าปัญหาคืออะไร
นี่คือข้อมูลสรุปสำหรับ 10, 100 และ 1,000 แถว - คุณจะเห็นได้ว่าการสืบค้น 1,000 แถวนั้นเป็นไปในทิศทางเดียวกันกับที่อื่น ๆ :
คุณจะเห็นว่าแบบสอบถามที่สามมีจำนวนการอ่านที่ไร้สาระดังนั้นจึงเห็นได้ชัดว่าการทำสิ่งที่แตกต่างอย่างสิ้นเชิง นี่คือแผนการดำเนินการโดยประมาณที่มีการนับแถว แผนการดำเนินการประมาณ 1,000 แถว:
และนี่คือผลลัพธ์ที่แท้จริงของแผนการดำเนินการ (ตามวิธีโดย "ไม่เสร็จสิ้น" ปรากฎว่าฉันหมายถึง "เสร็จสิ้นในหนึ่งชั่วโมง") แผนการดำเนินการจริง 1,000 แถว
สิ่งแรกที่ผมสังเกตเห็นก็คือว่าแทนที่จะดึง 60K แถวจากตาราง dimTime เช่นนั้นคาดว่าก็จริงดึง1600000000 กับ B ดูที่การสืบค้นของฉันฉันไม่แน่ใจว่ามันดึงแถวจำนวนมากออกจากตาราง dimTime อย่างไร ตัวดำเนินการระหว่างที่ฉันกำลังใช้เพียงแค่ให้แน่ใจว่าฉันดึงระเบียนที่ถูกต้องจาก #mac ตามบันทึกเวลาในตารางข้อเท็จจริง อย่างไรก็ตามเมื่อฉันเพิ่มบรรทัดในส่วนคำสั่ง WHERE ที่ฉันกรอง t.TimeValue (หรือ t.TimeID) เป็นค่าเดียวฉันสามารถอัปเดตแถว 100,000 แถวได้ในไม่กี่วินาที จากสิ่งนั้นและอย่างชัดเจนในแผนการดำเนินการที่ฉันรวมไว้มันชัดเจนว่าตารางเวลาของฉันเป็นปัญหา แต่ฉันไม่แน่ใจว่าฉันจะเปลี่ยนเกณฑ์การเข้าร่วมเพื่อแก้ไขปัญหานี้และรักษาความถูกต้องได้อย่างไร . ความคิดใด ๆ
สำหรับการอ้างอิงนี่คือแผน (พร้อมการนับแถว) สำหรับการอัปเดต 100 แถว คุณจะเห็นว่ามันไปถึงดัชนีเดียวกันและยังคงมีจำนวนแถวเป็นตัน แต่ไม่มีที่ไหนใกล้กับปัญหาที่มีขนาดเท่ากัน การดำเนินการ 100 แถวโดยมีจำนวนแถว :
from #mac sma join f on f.macid = sma.macid join dimTime t on f.TimeID = t.TimeID and t.TimeValue between sma.StartDate and sma.enddate
vsfrom #mac join t on t.TimeValue between sma.StartDate and sma.enddate join f on f.TimeID = t.TimeID and f.macid = sma.macid
TOP 50
ควรดำเนินการอย่างรวดเร็ว คุณสามารถอัปโหลดแผน XML ได้หรือไม่ ฉันต้องดูจำนวนแถว คุณสามารถรันTOP 50
with with maxdop 1 และเป็นตัวเลือกไม่ใช่เป็นการอัปเดตและโพสต์แผนหรือไม่ (พยายามทำให้ / ค้นหาพื้นที่เป็นสองเท่า)
t.TimeValue between sma.StartDate and sma.enddate
อาจจบลงสร้างแถวที่ไร้ประโยชน์มากขึ้นในภายหลังซึ่งถูกกรองออกจากการเข้าร่วมกับ FactSubscriber และดังนั้นอย่าจบลงด้วยผลลัพธ์สุดท้าย
sp_updatestatistics
บนโต๊ะหรือไม่?