คำใบ้ Tablock ทำให้เกิดการหยุดชะงัก


10

ฉันใส่ชุดข้อมูลสองชุดโดยใช้การบันทึกขั้นต่ำลงในตาราง heap ที่ว่างโดยใช้ Execute SQL Tasks สองชุดที่ทำงานแบบขนานและ SQL ในรูปแบบต่อไปนี้

INSERT INTO Table (TABLOCK) SELECT FROM ...

หลังจากงานหยุดทำงานหนึ่งในงาน SQL กลายเป็นเหยื่อการหยุดชะงัก ด้านล่างคือเอาต์พุต XML ของกราฟเดดล็อก

ใครสามารถอธิบายสิ่งที่เกิดขึ้นภายใต้ประทุนได้หรือไม่?

  <resource-list>
   <objectlock lockPartition="0" objid="1586156746" subresource="FULL" dbid="7" objectname="dbo.TargetTable" id="lock7374a00" mode="IX" associatedObjectId="1586156746">
    <owner-list>
     <owner id="process9609dc8" mode="Sch-S"/>
     <owner id="process9609dc8" mode="IX"/>
    </owner-list>
    <waiter-list>
     <waiter id="process5e13048" mode="X" requestType="convert"/>
    </waiter-list>
   </objectlock>
   <objectlock lockPartition="0" objid="1586156746" subresource="FULL" dbid="7" objectname="dbo.TargetTable" id="lock7374a00" mode="IX" associatedObjectId="1586156746">
    <owner-list>
     <owner id="process5e13048" mode="Sch-S"/>
     <owner id="process5e13048" mode="IX"/>
    </owner-list>
    <waiter-list>
     <waiter id="process9609dc8" mode="X" requestType="convert"/>
    </waiter-list>
   </objectlock>
  </resource-list>

สิ่งต่าง ๆ มีความซับซ้อนมากขึ้นเพราะฉันพบว่าในกรณีส่วนใหญ่งาน Execute SQL สองงานสามารถทำงานแบบขนานได้สำเร็จ ลองด้านล่าง:

Create table dbo.TablockInsert (c1 int, c2 int, c3 int)

--then issue the script in two Execute Sql Task in parallel you won't fail:
insert into dbo.TablockInsert(TABLOCK) SELECT 1, 1, 1

เนื่องจากความแตกต่างเพียงอย่างเดียวคือคำสั่ง SELECT ... จาก ... ดูเหมือนว่าคำสั่ง SELECT ... จาก ... อาจมีผลต่อโหมดล็อคได้ที่นี่


คุณสามารถระบุ TABLOCKX แทน TABLOCK เพื่อป้องกันการหยุดชะงัก แม้ว่าการทำเช่นนี้จะทำให้การเข้าถึงตารางเป็นแบบอนุกรมคุณยังจะได้รับการบันทึกขั้นต่ำ
Dan Guzman

คำตอบ:


8

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

การโหลดตารางที่ไม่มีพาร์ทิชั่นจำนวนมากที่ว่างเปล่า

การโหลดข้อมูลลงในตารางที่ไม่มีการแบ่งส่วนในขณะที่ใช้งานง่ายสามารถปรับให้เหมาะสมได้หลายวิธี

...

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

ในสถานการณ์นี้ทั้งINSERT … SELECTและ SELECT INTO มีข้อเสียเปรียบ ทั้งสองการดำเนินการเหล่านี้ใช้เอกสิทธิ์ (X) ล็อคระดับตารางในปลายทาง ซึ่งหมายความว่าการดำเนินการโหลดจำนวนมากเพียงครั้งเดียวสามารถทำงานในเวลาที่กำหนดซึ่งจำกัดความสามารถในการขยาย อย่างไรก็ตาม BCP, BULK INSERT และ Integration Services ทั้งหมดสามารถทำการล็อคเป็นกลุ่ม (BU) ได้หากคุณระบุ TABLOCK hint

ส่วนที่สำคัญคือการที่คุณไม่ได้รับล็อค BU INSERT ... SELECTกับ คุณจะได้รับการล็อคแบบเอกสิทธิ์บนโต๊ะเสมอดังนั้นจึงINSERTสามารถเรียกใช้ครั้งละหนึ่งรายการเท่านั้น

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

  1. เม็ดมีดหนึ่งเม็ดทำงานก่อนและบล็อกส่วนแทรกอื่น ๆ เม็ดมีดที่สองรอจนกระทั่งเม็ดมีดชุดแรกเสร็จสิ้น
  2. เม็ดมีดหนึ่งเม็ดเสร็จสิ้นก่อนที่เม็ดมีดที่สองจะเริ่มขึ้น ไม่มีการบล็อกที่ชัดเจน แต่จะไม่ทำงานพร้อมกัน
  3. คุณได้รับการหยุดชะงักและการแทรกเสร็จสมบูรณ์เพียงครั้งเดียว

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

สำหรับในสถานการณ์ที่แตกต่างที่คุณต้องการใช้การแทรกแบบขนานจริงๆสองวิธีในการแก้ไขปัญหา BU คือการแบ่งพาร์ติชันฮีปของคุณและให้แต่ละเซสชั่นแทรกลงในพาร์ติชันแยกต่างหากหรือโหลดข้อมูลของคุณผ่าน BCP, BULK INSERT หรือ Integration Services .


ขอบคุณสำหรับคำตอบ แต่สถานการณ์ที่ฉันพบการหยุดชะงักเป็นกรณีเดียวที่ฉันมีตอนนี้ สำหรับกรณีส่วนใหญ่เมื่อคุณออก INSERT INTO WITH (TABLOCK) SELECT จากแบบขนานงานจะไม่ล้มเหลว BTW ฉันใช้ SQL Server 2008 R2 ฉันได้เพิ่มตัวอย่างที่ประสบความสำเร็จในคำถามของฉัน
SqlWhale

@tec ในกรณีที่มันไม่ได้ล้มเหลวอย่างแน่นอนพวกเขาจะลงเอยด้วยการทำงานอย่างจริงจัง บางทีคุณอาจประสบปัญหาเมื่อมีเวลาเริ่มต้นที่แน่นอนเช่นสำหรับการรวบรวมแผน
Martin Smith

@MartinSmith แบบสอบถามที่ฉันพบปัญหาเกี่ยวกับโครงการนั้นซับซ้อนกว่าตัวอย่าง SELECT 1 ซึ่งต้องการการคอมไพล์โอเวอร์เฮดมากขึ้น แต่เป็นเพียงการอ่านจากสองตาราง ฉันพยายามที่จะทำซ้ำการหยุดชะงักประเภทนี้โดยการค้นหาที่ซับซ้อนมากขึ้น
SqlWhale

@TecKnowNothing เกี่ยวกับคุณแทรกแถวกี่แถว? กระบวนการทำงานวันละกี่ครั้ง คำสั่งอื่น ๆ เลือกจากตารางขณะที่โหลดข้อมูลหรือไม่
โจ Obbish

@ JoeObbish 1. ฉันไม่คิดว่า # ของแถวเป็นปัญหาที่นี่เรามีเพียง 4,000 - 70000 ต่อการสืบค้นแต่ละครั้ง 2. มันยังอยู่ในขั้นตอนการทดสอบควรทำงานวันละครั้ง 3. ไม่มีอะไรอื่นอ่านจากตารางเป้าหมาย
SqlWhale

4

คุณกำลังแทรกdbo.TargetTableจากสองเซสชันและทั้งสองใช้TABLOCKhintBoth process9609dc8และprocess5e13048กระบวนการจับSch-SและIXล็อคที่เข้ากันได้เพื่อให้กระบวนการทั้งสองสามารถถือในเวลาเดียวกัน แต่ทั้งคู่ต้องการแปลงIXล็อคเป็นExclusive Xประเภท Xล็อคเข้ากันไม่ได้ ดังนั้นเซิร์ฟเวอร์ SQL จึงเลือกหนึ่งในเซสชั่นเป็นเหยื่อการหยุดชะงักแทนการรอคอยซึ่งกันและกันอย่างไม่สิ้นสุด

ข้อมูลการหยุดชะงักขั้นพื้นฐาน

แผนภูมิความเข้ากันได้ของล็อก (โปรแกรมฐานข้อมูล)

การตรวจจับและการสิ้นสุด Deadlocks

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