วิธีรับการแทรก SQL และ / หรือการปรับปรุงเพื่อไม่ล็อคทั้งตารางใน MS SQL Server


13

มือใหม่ในฐานข้อมูลทำงานมากดังนั้นขอขอบคุณที่กรุณาอดทนรอด้วยคำถามพื้นฐาน ฉันใช้ SQL Server 2014 บนเครื่องของฉันและฉันมีตารางเล็ก ๆ และแอปพลิเคชันไคลเอนต์ขั้นพื้นฐานเพื่อทดสอบวิธีการต่าง ๆ ด้วย ฉันได้สิ่งที่ดูเหมือนจะล็อคตารางระหว่างทั้งสองINSERT INTOและUPDATEงบ ไคลเอนต์เป็นแอปพลิเคชัน ASP.NET ด้วยรหัสต่อไปนี้:

OleDbConnection cn = new OleDbConnection("Provider=SQLNCLI11; server=localhost\\SQLEXPRESS; Database=<my db>; user id=<my uid>; password=<my pwd>");
cn.Open();
OleDbTransaction tn = cn.BeginTransaction();
OleDbCommand cmd = new OleDbCommand("INSERT INTO LAYOUTSv2 (LAYOUTS_name_t, LAYOUTS_enabled_b, LAYOUTS_data_m) VALUES ('name', '-1', 'data')", cn, tn);
cmd.ExecuteNonQuery();
cmd.CommandText = "SELECT SCOPE_IDENTITY()";
int newkey = Decimal.ToInt32((decimal)cmd.ExecuteScalar());
Console.WriteLine("Created index " + newkey);
Thread.Sleep(15000);
tn.Commit();
tn = cn.BeginTransaction();
cmd.CommandText = "UDPATE LAYOUTSv2 SET LAYOUTS_enabled_b='-3' WHERE LAYOUTS_key='" + newkey + "'";
cmd.Transaction = tn;
cmd.ExecuteNonQuery();
Console.WriteLine("updated row");
Thread.Sleep(15000);
tn.Rollback();
cn.Close();

SELECT * FROM LAYOUTSv2ฉันเรียกใช้รหัสนี้แล้วจากการบริหารจัดการสตูดิโอผมวิ่ง ระหว่างทั้งสองกรณีเมื่อไคลเอ็นต์เธรดถูกหยุดชั่วคราว (เช่นก่อนที่จะคอมมิต / ย้อนกลับ) เคียวรี SELECT จะค้างจนกว่าการคอมมิชชัน / การย้อนกลับจะเกิดขึ้น

ตารางมีฟิลด์ LAYOUTS_key ที่กำหนดเป็นคีย์หลัก ในหน้าต่างคุณสมบัติมันแสดงให้เห็นว่ามันเป็นเอกลักษณ์และคลัสเตอร์ที่มีการล็อคหน้าและล็อคแถวทั้งสองได้รับอนุญาต การตั้งค่าการเลื่อนล็อคสำหรับตารางนั้นปิดใช้งาน ... ฉันได้ลองทั้งการตั้งค่าอื่น ๆ ที่มีในตารางและอัตโนมัติโดยไม่มีการเปลี่ยนแปลง ฉันได้พยายามSELECT ... WITH (NOLOCK)และผลตอบแทนผลทันที แต่เป็นเป็นอย่างดีเตือนที่นี่และที่อื่น ๆ มันไม่ได้เป็นสิ่งที่ฉันควรจะทำ ฉันได้ลองใส่ROWLOCKคำใบ้ทั้งบนINSERTและUPDATEข้อความ แต่ก็ไม่มีอะไรเปลี่ยนแปลง

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


3
โดยวิธีWHERE LAYOUTS_key='" + newkey + "'การที่ไม่มีความสมบูรณ์ด้วยเหตุผลต่างๆรวมถึงการฉีด SQL คุณควรใช้แบบสอบถามแบบใช้พารามิเตอร์
Martin Smith

1
@MartinSmith ขอบคุณสำหรับเรื่องนี้ ... ไม่เคยได้ยินแบบสอบถามที่กำหนดพารามิเตอร์หรือการโจมตี SQL Injection
John Riehl

@JohnRiehl อีกครั้ง: การโจมตีด้วยการฉีดจินตนาการว่าผู้ใช้ของคุณตั้งค่าnewkeyเป็น " something';DELETE FROM LAYOUTSv2 --" การอัปเดตของคุณจะเสร็จสมบูรณ์แล้วจากนั้นทำให้ตารางว่างเปล่าเนื่องจากผู้ใช้จัดการแบบสอบถามโดยใส่เครื่องหมายอัญประกาศเดี่ยว โดยทั่วไปแบบสอบถามที่มีพารามิเตอร์จะมีลักษณะดังนี้UDPATE LAYOUTSv2 SET LAYOUTS_enabled_b='-3' WHERE LAYOUTS_key=?หลังจากที่คุณกำหนดค่าให้กับ?(พารามิเตอร์) ในรหัสของคุณ
Daniel Hutmacher

คำตอบ:


10

โอกาสที่มันจะไม่ล็อค "ทั้งตาราง"

มันกำลังล็อคแถวในตาราง แต่คุณSELECT * FROM LAYOUTSv2พยายามอ่านทั้งตารางดังนั้นจำเป็นต้องถูกบล็อกโดยล็อคนั้น

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

ถ้าคุณกำหนดค่าฐานข้อมูลสำหรับการแยกภาพรวมอ่านความมุ่งมั่นนี้จะให้ผลที่ต้องการของคุณทั้งสองกรณี (ที่ค่าใช้จ่ายในการใช้งานที่มากขึ้นของtempdb)


ฉันเปลี่ยน "Is Read Committed Snapshot On" เป็น True และตอนนี้ทำงานได้อย่างสมบูรณ์แบบโดยไม่จำเป็นต้องมีคำแนะนำใด ๆ ขอบคุณ! หนึ่งการติดตาม ... ฉันออกจาก "อนุญาตให้ใช้ Snapshot Isolation" เป็น False ... ตกลงไหม ขอบคุณ
John Riehl

@JohnRiehl - ใช่หากคุณไม่ได้ใช้SNAPSHOTการแยกอย่างชัดเจนที่สุดให้ปิดการใช้งานและเปิดใช้งานหากคุณตัดสินใจในภายหลังว่านี่จะเป็นประโยชน์สำหรับคุณ
Martin Smith

7

คำสั่งแทรกและอัพเดตควรจะสร้างการล็อกระดับแถว อย่างไรก็ตามเมื่อจำนวนการล็อคในการทำธุรกรรมใด ๆ เป็น 5,000 หรือมากกว่านั้นการเพิ่มการล็อคเกิดขึ้นและจะสร้างการล็อคระดับตาราง โปรดดูที่ด้านล่าง.

https://technet.microsoft.com/en-us/library/ms184286(v=sql.105).aspx


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