ความแตกต่างระหว่าง“ อ่านแล้ว” และ“ อ่านซ้ำได้”


245

ฉันคิดว่าระดับความโดดเดี่ยวที่กล่าวมานั้นเหมือนกัน มีคนช่วยอธิบายด้วยตัวอย่างดีๆได้ไหมความแตกต่างหลักคืออะไร


3
คุณควรขยายคำถามและเพิ่มแท็กสำหรับ "ระดับการแยก" ที่คุณอ้างถึง (Java, ฯลฯ ) "ระดับการแยก" เป็นคำที่ค่อนข้างคลุมเครือและเห็นได้ชัดว่าคุณกำลังขอคำตอบสำหรับสภาพแวดล้อมที่เฉพาะเจาะจง
jesup

คำตอบ:


564

ความมุ่งมั่นในการอ่านคือระดับการแยกที่รับประกันว่าข้อมูลใด ๆ ที่อ่านได้กระทำในขณะที่อ่าน มัน จำกัด ผู้อ่านจากการมองเห็นการอ่านระดับกลาง, ไม่ จำกัด , 'สกปรก' ไม่มีสัญญาใด ๆ ว่าหากธุรกรรมซ้ำการอ่านจะพบข้อมูลเดียวกันข้อมูลมีอิสระในการเปลี่ยนแปลงหลังจากที่อ่านแล้ว

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

ระดับการแยกถัดไปเป็นแบบอนุกรมทำให้การรับประกันแข็งแกร่งยิ่งขึ้น: นอกเหนือจากการรับประกันการอ่านที่ทำซ้ำได้ทุกอย่างแล้วยังรับประกันได้ว่าจะไม่มีข้อมูลใหม่ที่สามารถอ่านได้ในภายหลัง

สมมติว่าคุณมีตาราง T ที่มีคอลัมน์ C และมีหนึ่งแถวในแถวนั้นว่ามันมีค่า '1' และพิจารณาว่าคุณมีงานง่าย ๆ ดังต่อไปนี้:

BEGIN TRANSACTION;
SELECT * FROM T;
WAITFOR DELAY '00:01:00'
SELECT * FROM T;
COMMIT;

นั่นเป็นงานง่ายที่ให้ผู้อ่านสองคนอ่านจากตาราง T โดยมีความล่าช้า 1 นาทีระหว่างกัน

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

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

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

อ่านเพิ่มเติม:


24
ฉันคิดว่ามีข้อผิดพลาดด้านบนสำหรับ REPEATABLE READ: คุณบอกว่าแถวที่มีอยู่ไม่สามารถลบหรือเปลี่ยนแปลงได้ แต่ฉันคิดว่าพวกเขาสามารถลบหรือเปลี่ยนแปลงได้เพราะอ่านซ้ำได้เพียงแค่อ่าน "snapshot" ไม่ใช่ข้อมูลจริง จาก docs dev.mysql.com/doc/refman/5.0/en/ … : "การอ่านที่สอดคล้องกันทั้งหมดภายในธุรกรรมเดียวกันอ่านสแน็ปช็อตที่สร้างโดยการอ่านครั้งแรก"
Derek Litz

2
@ Derek Litz ฉันว่าคุณกำลังพูดว่า: ข้อมูลสามารถ / อาจมีการเปลี่ยนแปลงจากบุคคลที่สามในขณะที่การทำธุรกรรมที่เกิดขึ้น แต่การอ่านจะยังคงเห็นข้อมูลเดิม 'เก่า' ราวกับว่าการเปลี่ยนแปลงไม่ได้ดำเนินการ สถานที่ (ภาพรวม)
โปรแกรม

5
@Cornstalks ใช่การอ่านแบบ Phantom สามารถเกิดขึ้นได้จากการลบ (หรือแทรก) ใช่การอ่านแบบแฝงสามารถเกิดขึ้นได้ในการแยกการอ่านซ้ำ (จากส่วนแทรกเท่านั้น) ไม่ได้ Phantom อ่านจากการลบไม่สามารถเกิดขึ้นได้ในการแยกการอ่านซ้ำ ทดสอบมัน สิ่งที่ฉันพูดไม่ได้ขัดแย้งกับเอกสารที่คุณอ้างถึง
AndyBrown

4
@Cornstalks NP ฉันพูดถึงเพียงเพราะฉันไม่แน่ใจ 100% ตัวเองและต้องดำน้ำลึกเพื่อให้แน่ใจว่าใครถูก! และฉันไม่ต้องการให้ผู้อ่านในอนาคตเข้าใจผิด การเก็บความคิดเห็นนั้นอาจเป็นการรักษาที่ดีที่สุดตามที่แนะนำ ฉันแน่ใจว่าทุกคนที่สนใจในรายละเอียดในระดับนั้นจะเฉพาะเจาะจงมากพอที่จะอ่านความคิดเห็นทั้งหมด !!
AndyBrown

12
ขอบคุณที่ไม่ลบความคิดเห็นของคุณ การสนทนาช่วยเชื่อมต่อจุดมากขึ้น
Josh

68

อ่านซ้ำ

สถานะของฐานข้อมูลได้รับการปรับปรุงจากจุดเริ่มต้นของการทำธุรกรรม หากคุณดึงค่าใน session1 จากนั้นอัปเดตค่านั้นใน session2 การดึงอีกครั้งใน session1 จะส่งคืนผลลัพธ์เดียวกัน การอ่านสามารถทำซ้ำได้

session1> BEGIN;
session1> SELECT firstname FROM names WHERE id = 7;
Aaron

session2> BEGIN;
session2> SELECT firstname FROM names WHERE id = 7;
Aaron
session2> UPDATE names SET firstname = 'Bob' WHERE id = 7;
session2> SELECT firstname FROM names WHERE id = 7;
Bob
session2> COMMIT;

session1> SELECT firstname FROM names WHERE id = 7;
Aaron

อ่านความมุ่งมั่น

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

session1> BEGIN;
session1> SELECT firstname FROM names WHERE id = 7;
Aaron

session2> BEGIN;
session2> SELECT firstname FROM names WHERE id = 7;
Aaron
session2> UPDATE names SET firstname = 'Bob' WHERE id = 7;
session2> SELECT firstname FROM names WHERE id = 7;
Bob
session2> COMMIT;

session1> SELECT firstname FROM names WHERE id = 7;
Bob

มีเหตุผล?


ฉันลองอ่านซ้ำใน SQL Server 2008 ด้วย "การตั้งค่าระดับการแยกซ้ำอ่านได้" สร้างหน้าต่างคิวรีสอง sql แต่ไม่ได้ผล ทำไม?
Aditya Bokade

1
ทำไมเซสชั่นที่สองจะยังอ่านแอรอน? การทำธุรกรรมของ session2 ไม่เสร็จสิ้นและตกลงใช่ไหม ฉันรู้ว่านี่เก่า แต่บางทีใครบางคนสามารถหลั่งน้ำตาแสง
Sonny Childs

9
ฉันคิดว่าการอ่านซ้ำจะปิดกั้นเซสชันที่สองจนกระทั่งเซสชันแรกที่ส่งมอบ ดังนั้นตัวอย่างผิด
Nighon

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

ฉันคิดว่าเซิร์ฟเวอร์ SQL และ MySQL ทำงานแตกต่างกันเมื่อพูดถึงการอัพเดทแถวที่ใช้ร่วมกันระหว่างสองธุรกรรม
user2488286

23

เพียงคำตอบตามที่ฉันอ่านและทำความเข้าใจกับเธรดนี้และคำตอบ @ remus-rusanu ขึ้นอยู่กับสถานการณ์อย่างง่าย ๆ นี้:

มีสองกระบวนการ A และ B กระบวนการ B กำลังอ่านตาราง X กระบวนการ A กำลังเขียนในตาราง X กระบวนการ B กำลังอ่านอีกครั้งตาราง X

  • ReadUncommitted : กระบวนการ B สามารถอ่านข้อมูลที่ไม่มีข้อผูกมัดได้จากกระบวนการ A และสามารถเห็นแถวที่แตกต่างกันโดยขึ้นอยู่กับการเขียน B ไม่มีล็อคเลย
  • ReadCommitted : กระบวนการ B สามารถอ่านข้อมูลที่ได้รับมอบหมายเท่านั้นจากกระบวนการ A และสามารถเห็นแถวที่แตกต่างกันโดยขึ้นอยู่กับการเขียน B แบบ COMMITTED เท่านั้น เราจะเรียกมันว่า Simple Lock ได้ไหม?
  • RepeatableRead : กระบวนการ B จะอ่านข้อมูลเดียวกัน (แถว) เมื่อกระบวนการ A กำลังดำเนินการอยู่ แต่กระบวนการ A สามารถเปลี่ยนแถวอื่นได้ แถวระดับบล็อก
  • Serialisable : กระบวนการ B จะอ่านแถวเดียวกับก่อนหน้านี้และกระบวนการ A ไม่สามารถอ่านหรือเขียนในตาราง บล็อกระดับตาราง
  • Snapshot : ทุกกระบวนการมีสำเนาของตัวเองและพวกเขากำลังทำงานอยู่ แต่ละคนมีมุมมองของตัวเอง

15

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

อ่านแล้วยอมรับ (ค่าเริ่มต้น)

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

อ่านซ้ำได้

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


13

พยายามอธิบายข้อสงสัยนี้ด้วยไดอะแกรมอย่างง่าย

อ่านความมุ่งมั่น: ที่นี่ในระดับการแยกนี้ธุรกรรม T1 จะอ่านค่าที่อัพเดตของ X ที่คอมมิทด้วยธุรกรรม T2

อ่านความมุ่งมั่น

อ่านซ้ำได้:ในระดับการแยกนี้ธุรกรรม T1 จะไม่พิจารณาการเปลี่ยนแปลงที่ทำโดยธุรกรรม T2

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


1

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

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


0

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


-1

การสังเกตของฉันเกี่ยวกับวิธีแก้ปัญหาที่ยอมรับครั้งแรก

ภายใต้ RR (ค่าเริ่มต้น mysql) - หากเปิด tx และ SELECT ถูกไล่ออกแล้ว tx อื่นไม่สามารถลบแถวใด ๆ ที่เป็นของชุดผลลัพธ์การอ่านก่อนหน้าจนกว่าจะมีการยืนยัน tx ก่อนหน้า (ในความเป็นจริงลบคำสั่งใน tx ใหม่ อย่างไรก็ตาม tx ถัดไปสามารถลบแถวทั้งหมดออกจากตารางได้โดยไม่มีปัญหา Btw การอ่านครั้งต่อไปใน tx ก่อนหน้าจะยังคงเห็นข้อมูลเก่าจนกว่าจะมีการส่งข้อมูล


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