เหตุผลที่ดีในการใช้ SELECT ... ด้วย XLOCK


11

ฉันกำลังเผชิญหน้ากับการหยุดชะงักที่เกิดขึ้นอีกครั้งหนึ่งในนั้นคือ Keylock และมีการสืบค้น SELECT พร้อมคำใบ้ XLOCK ที่กลายเป็นเหยื่อการหยุดชะงัก คำสั่งอื่น ๆ คือการแทรกลงในหนึ่งในตารางที่เป็นส่วนหนึ่งของมุมมองของแบบสอบถามแรก

ดู:

create view dbo.viewE
 as
    select * from dbo.E  
    where myValue > 13000 

เลือกคำค้นหา:

select * from dbo.viewE with (XLOCK) where A > GETUTCDATE() 

คำสั่ง INSERT:

INSERT INTO [dbo].[E] (myValue,A) VALUES (10,GetDate())

ตารางต้นแบบ dbo.E มีพื้นที่ประมาณ 3 ล้านแถวในประมาณ 20 คอลัมน์บางส่วนเป็น ntext

นำแบบสอบถามออกมาและจำลองสถานการณ์ด้วยตนเองด้วยธุรกรรมสองรายการลักษณะการทำงานจะสามารถผลิตซ้ำได้ พฤติกรรมจะเปลี่ยนไปหาก XLOCK ถูกลบออกจากตัวเลือก

กราฟการหยุดชะงัก:

<deadlock-list>
 <deadlock victim="process222222221">
  <process-list>
   <process id="process222222221" taskpriority="0" logused="0" waitresource="KEY: 5:72057604035644444 (ccdf51accc0c)" waittime="2522" ownerId="27202256401" transactionname="SELECT" lasttranstarted="2015-09-14T16:32:36.160" XDES="0x2f1ec5ca0" lockMode="RangeX-X" schedulerid="15" kpid="12936" status="suspended" spid="359" sbid="0" ecid="0" priority="0" trancount="0" lastbatchstarted="2015-09-14T16:32:36.160" lastbatchcompleted="2015-09-14T16:32:36.160" clientapp="x" hostname="x" hostpid="14536" loginname="x" isolationlevel="serializable (4)" xactid="27202256401" currentdb="5" lockTimeout="4294967295" clientoption1="671088672" clientoption2="128056">
    <executionStack>
     <frame procname="adhoc" line="1" stmtstart="48" sqlhandle="0x02000000611e4523142b2318c47c87313a9b2ba587ff3130">
        SELECT * FROM viewE WITH (XLOCK) WHERE A &lt; GetUtcDate()      </frame>
     <frame procname="unknown" line="1" sqlhandle="0x000000000000000000000000000000000000000000000000">
unknown     </frame>
    </executionStack>
    <inputbuf>
(@UICulture nvarchar(5))SELECT * FROM viewE WITH (XLOCK) WHERE A &lt; GetUtcDate()    </inputbuf>
   </process>
   <process id="process6022222" taskpriority="0" logused="161152" waitresource="KEY: 5:72057604035644444 (cd874c2ba438)" waittime="1370" ownerId="27202248438" transactionguid="0x8de5ccd6eeef67469c6234af59e44ca5" transactionname="DTCXact" lasttranstarted="2015-09-14T16:32:34.767" XDES="0x4aa0bf950" lockMode="RangeI-N" schedulerid="14" kpid="6636" status="suspended" spid="329" sbid="0" ecid="0" priority="0" trancount="2" lastbatchstarted="2015-09-14T16:32:37.300" lastbatchcompleted="2015-09-14T16:32:37.300" clientapp="x" hostname="x" hostpid="14536" loginname="x" isolationlevel="read uncommitted (1)" xactid="27202248438" currentdb="5" lockTimeout="4294967295" clientoption1="671088672" clientoption2="128056">
    <executionStack>
     <frame procname="adhoc" line="1" stmtstart="936" sqlhandle="0x020000004853462f09790a4ddedc0d574c2afa539aef1c0e">
     INSERT INTO [E] ([a], [b], [c],...) VALUES (@aDate, @bDate, @c, ...)
     </frame>
     <frame procname="unknown" line="1" sqlhandle="0x000000000000000000000000000000000000000000000000">
unknown     </frame>
    </executionStack>
    <inputbuf>INSERT INTO [E] ([a], [b], [c],...) VALUES (@aDate, @bDate, @c, ...)
    </inputbuf>
   </process>
  </process-list>
  <resource-list>
   <keylock hobtid="72057604035644444" dbid="5" objectname="db.dbo.E" indexname="IX_index1" id="lock258b6dc80" mode="X" associatedObjectId="72057604035644444">
    <owner-list>
     <owner id="process6022222" mode="X"/>
    </owner-list>
    <waiter-list>
     <waiter id="process222222221" mode="RangeX-X" requestType="wait"/>
    </waiter-list>
   </keylock>
   <keylock hobtid="72057604035644444" dbid="5" objectname="db.dbo.E" indexname="IX_index1" id="lock7b145c400" mode="RangeX-X" associatedObjectId="72057604035644444">
    <owner-list>
     <owner id="process222222221" mode="RangeX-X"/>
    </owner-list>
    <waiter-list>
     <waiter id="process6022222" mode="RangeI-N" requestType="wait"/>
    </waiter-list>
   </keylock>
  </resource-list>
 </deadlock>
</deadlock-list>

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

คำถามของฉัน:

  1. ฉันไม่สามารถสร้างดัชนีการครอบเพราะมีคอลัมน์ NTEXT ที่เกี่ยวข้อง จะลดจำนวนแถวลงอย่างมากหรือไม่
  2. มีเหตุผลที่ดีที่ฉันไม่ทราบว่า SELECT ถูกดำเนินการด้วย XLOCK หรือไม่ การหยุดชะงักจะเกิดขึ้นหากไม่มี XLOCK หรือไม่

คำตอบ:


15

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

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

จะลดจำนวนแถวลงอย่างมากหรือไม่

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

มีเหตุผลที่ดีที่ฉันไม่ทราบว่า SELECT ถูกดำเนินการด้วย XLOCK หรือไม่

ไม่ได้จริงๆ คำแนะนำในการล็อคเช่นนี้มักได้รับการแนะนำให้รู้จักกับคนโดยปราศจากความเข้าใจอย่างถ่องแท้เกี่ยวกับการแยกการล็อกและการหยุดชะงักในความพยายามอย่างยิ่งยวดที่จะลดหรือขจัดปัญหา

การหยุดชะงักจะเกิดขึ้นหากไม่มี XLOCK หรือไม่

ไม่หากการเลือกทำงานจริงที่การแยกแบบไม่มีข้อผูกมัดอ่านเนื่องจากการล็อกที่เข้ากันไม่ได้จะไม่ถูกดำเนินการ (และคงไว้) ในลำดับอื่น

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

คำแนะนำ

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

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

หากแอปพลิเคชันของคุณและโค้ด SQL Server สามารถทนต่อการอ่านแถวได้การเปลี่ยนเป็นการอ่านสแน็ปช็อตการแยก (RCSI) หรือสแน็ปช็อตการแยก (SI) สำหรับการอ่านจะช่วยหลีกเลี่ยงการหยุดชะงัก ( XLOCKลบออก!) มุมมองเวลาของข้อมูลที่กำหนด สิ่งนี้ยังถือว่าคุณสามารถหลีกเลี่ยงการแยกได้แบบอนุกรมได้

ในที่สุดXLOCKคำใบ้นั้นตอบโต้ได้ดี แต่คุณต้องพิจารณาถึงเหตุผลในการใช้ระดับการแยกแบบอนุกรมได้ สิ่งที่trancount = 2น่าสนใจก็คือบางทีคุณอาจทำธุรกรรมโดยไม่ได้ตั้งใจที่นี่ อย่างอื่นที่จะตรวจสอบ


2
  1. การลดจำนวนแถวลงอย่างมากจะช่วยลดโอกาสที่จะเกิดการหยุดชะงัก แต่มันจะไม่หายไปอย่างสมบูรณ์

กล่าวง่ายๆคือการเลือกใช้ดัชนีเพื่อกำหนดแถวให้เลือกจากนั้นดึงแถวในขณะที่การแทรกแทรกแถวแล้วพยายามอัปเดตดัชนี (XLOCKED)

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

ต้องบอกว่าการลบ XLOCK อาจไม่สามารถแก้ไขปัญหาได้ SELECT จะยังคงล็อคที่ใช้ร่วมกันในดัชนีและ INSERT จะต้องการ XLOCK เพื่ออัปเดต ล็อคที่ใช้ร่วมกันและ XLOCK ไม่สามารถอยู่บนวัตถุด้วยกันดังนั้นคุณจะยังคงได้รับการหยุดชะงัก IX_Index1 ต้องเป็น MyValue หรือ A หรือทั้งสองอย่าง

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

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