Mat และ Erwin นั้นถูกต้องแล้วและฉันแค่เพิ่มคำตอบเพื่อขยายสิ่งที่พวกเขาพูดในแบบที่ไม่เหมาะสมกับความคิดเห็น เนื่องจากคำตอบของพวกเขาดูเหมือนจะไม่เป็นที่พอใจของทุกคนและมีข้อเสนอแนะที่นักพัฒนา PostgreSQL ควรได้รับการพิจารณาและฉันเป็นหนึ่งเดียวฉันจะทำอย่างละเอียด
จุดสำคัญที่นี่คือว่าภายใต้มาตรฐาน SQL ภายในธุรกรรมที่รันที่READ COMMITTED
ระดับการแยกธุรกรรมข้อ จำกัด คือการทำงานของธุรกรรมที่ปราศจากข้อผูกมัดจะต้องมองไม่เห็น เมื่องานของการทำธุรกรรมที่เกิดขึ้นกลายเป็นสิ่งที่มองเห็นได้ สิ่งที่คุณกำลังชี้ให้เห็นคือความแตกต่างในวิธีที่สองผลิตภัณฑ์ได้เลือกใช้งาน การใช้งานไม่ได้ละเมิดข้อกำหนดของมาตรฐาน
นี่คือสิ่งที่เกิดขึ้นภายใน PostgreSQL โดยละเอียด:
S1-1 ทำงาน (ลบ 1 แถว)
แถวเก่าถูกทิ้งไว้เนื่องจาก S1 อาจยังย้อนกลับ แต่ตอนนี้ S1 มีการล็อกแถวเพื่อให้เซสชันอื่น ๆ ที่พยายามแก้ไขแถวจะรอเพื่อดูว่า S1 กระทำหรือย้อนกลับ ใด ๆอ่านของตารางยังสามารถดูแถวเก่าจนกว่าพวกเขาพยายามที่จะล็อคด้วยหรือSELECT FOR UPDATE
SELECT FOR SHARE
S2-1 ทำงาน (แต่ถูกบล็อกเนื่องจาก S1 มีล็อคการเขียน)
ตอนนี้ S2 ต้องรอดูผลลัพธ์ของ S1 หาก S1 ต้องย้อนกลับแทนที่จะคอมมิชชัน S2 จะลบแถวนั้น โปรดทราบว่าหาก S1 แทรกเวอร์ชันใหม่ก่อนจะย้อนกลับเวอร์ชันใหม่จะไม่เคยอยู่ในมุมมองของธุรกรรมอื่น ๆ และจะไม่ลบเวอร์ชันเก่าออกจากมุมมองของธุรกรรมอื่น ๆ
S1-2 ทำงาน (แทรก 1 แถว)
แถวนี้เป็นอิสระจากแถวเก่า หากมีการอัปเดตของแถวที่มี id = 1 เวอร์ชันเก่าและใหม่จะเกี่ยวข้องกันและ S2 สามารถลบเวอร์ชันที่อัปเดตของแถวได้เมื่อไม่ถูกบล็อก การที่แถวใหม่เกิดขึ้นจะมีค่าเหมือนกันกับบางแถวที่มีอยู่ในอดีตไม่ได้ทำให้เหมือนกันกับเวอร์ชันที่อัปเดตของแถวนั้น
S1-3 ทำงานปล่อยการล็อกการเขียน
ดังนั้นการเปลี่ยนแปลงของ S1 จึงยังคงอยู่ หายไปหนึ่งแถว เพิ่มหนึ่งแถวแล้ว
S2-1 ทำงานทันทีที่สามารถล็อคได้ แต่รายงานถูกลบ 0 แถว ฮะ???
สิ่งที่เกิดขึ้นภายในคือมีตัวชี้จากหนึ่งเวอร์ชันของแถวไปเป็นเวอร์ชันถัดไปของแถวเดียวกันนั้นหากมีการอัพเดต หากลบแถวจะไม่มีรุ่นถัดไป เมื่อทREAD COMMITTED
รานแซคชันตื่นขึ้นมาจากบล็อกบนข้อขัดแย้งในการเขียนรายการนั้นจะติดตามสายโซ่นั้นจนจบ หากแถวยังไม่ถูกลบและหากยังคงเป็นไปตามเกณฑ์การเลือกของแบบสอบถามจะถูกประมวลผล แถวนี้ถูกลบไปแล้วดังนั้นการค้นหาของ S2 จะดำเนินต่อไป
S2 อาจหรือไม่ได้รับแถวใหม่ในระหว่างการสแกนของตาราง หากเป็นเช่นนั้นจะเห็นว่าแถวใหม่ถูกสร้างขึ้นหลังจากDELETE
คำสั่งของ S2 เริ่มต้นขึ้นและไม่ได้เป็นส่วนหนึ่งของชุดแถวที่มองเห็นได้
หาก PostgreSQL ต้องเริ่มต้นงบ DELETE ทั้งหมดของ S2 ใหม่ตั้งแต่เริ่มต้นด้วยสแนปชอตใหม่มันจะทำงานเหมือน SQL Server ชุมชน PostgreSQL ไม่ได้เลือกที่จะทำเช่นนั้นด้วยเหตุผลด้านประสิทธิภาพ ในกรณีง่าย ๆ นี้คุณจะไม่สังเกตเห็นความแตกต่างของประสิทธิภาพ แต่ถ้าคุณมีสิบล้านแถวในDELETE
เมื่อคุณถูกบล็อกคุณจะต้องแน่นอน มีการแลกเปลี่ยนที่นี่ที่ PostgreSQL เลือกประสิทธิภาพเนื่องจากรุ่นที่เร็วกว่านั้นยังคงเป็นไปตามข้อกำหนดของมาตรฐาน
S2-2 ทำงานรายงานการละเมิดข้อ จำกัด คีย์ที่ไม่ซ้ำกัน
แน่นอนแถวนั้นมีอยู่แล้ว นี่เป็นส่วนที่น่าแปลกใจที่สุดของภาพ
ในขณะที่มีพฤติกรรมที่น่าแปลกใจบางอย่างที่นี่ทุกอย่างสอดคล้องกับมาตรฐาน SQL และภายในขอบเขตของ "การใช้งานเฉพาะ" ตามมาตรฐาน แน่นอนว่าอาจเป็นเรื่องที่น่าแปลกใจหากคุณสมมติว่าพฤติกรรมของการนำไปใช้งานอื่น ๆ นั้นมีอยู่ในการนำไปใช้ทั้งหมด แต่ PostgreSQL พยายามอย่างหนักเพื่อหลีกเลี่ยงความล้มเหลวของการทำให้เป็นอนุกรมในREAD COMMITTED
ระดับแยกและทำให้พฤติกรรมบางอย่างที่แตกต่างจากผลิตภัณฑ์อื่น ๆ
ตอนนี้ส่วนตัวผมไม่ได้เป็นแฟนตัวยงของREAD COMMITTED
ระดับแยกธุรกรรมในใด ๆการดำเนินงานของผลิตภัณฑ์ พวกเขาทั้งหมดอนุญาตให้เงื่อนไขการแข่งขันเพื่อสร้างพฤติกรรมที่น่าแปลกใจจากมุมมองของการทำธุรกรรม เมื่อมีคนคุ้นเคยกับพฤติกรรมแปลก ๆ ที่ได้รับอนุญาตจากผลิตภัณฑ์หนึ่งพวกเขามักจะพิจารณาว่า "ปกติ" และการแลกเปลี่ยนที่ถูกเลือกโดยผลิตภัณฑ์อื่นที่แปลก แต่ทุกผลิตภัณฑ์เพื่อให้มีการจัดเรียงของบางอย่างการปิดสำหรับโหมดใด ๆ SERIALIZABLE
ที่ไม่ใช้งานจริงเป็น จุดที่นักพัฒนา PostgreSQL เลือกที่จะลากเส้นREAD COMMITTED
คือการลดการบล็อกให้น้อยที่สุด (อ่านไม่บล็อกการเขียนและการเขียนไม่บล็อกอ่าน) และเพื่อลดโอกาสของความล้มเหลวในการทำให้เป็นอนุกรม
มาตรฐานกำหนดให้การSERIALIZABLE
ทำธุรกรรมเป็นค่าเริ่มต้น แต่ผลิตภัณฑ์ส่วนใหญ่ไม่ทำเช่นนั้นเพราะทำให้ประสิทธิภาพการทำงานเหนือระดับการแยกธุรกรรมหละหลวมมากขึ้น ผลิตภัณฑ์บางอย่างไม่ได้จัดทำธุรกรรมที่สามารถทำให้เป็นอนุกรมได้อย่างแท้จริงเมื่อSERIALIZABLE
เลือก - โดยเฉพาะอย่างยิ่ง Oracle และเวอร์ชันของ PostgreSQL ก่อนหน้า 9.1 แต่การใช้SERIALIZABLE
ธุรกรรมอย่างแท้จริงเป็นวิธีเดียวที่จะหลีกเลี่ยงผลกระทบที่น่าประหลาดใจจากสภาพการแข่งขันและการSERIALIZABLE
ทำธุรกรรมจะต้องปิดกั้นเพื่อหลีกเลี่ยงสภาพการแข่งขันหรือย้อนกลับธุรกรรมบางอย่างเพื่อหลีกเลี่ยงสภาพการแข่งขันที่กำลังพัฒนา การใช้งานSERIALIZABLE
ธุรกรรมที่พบบ่อยที่สุดคือ Strict Two-Phase Locking (S2PL) ซึ่งมีทั้งการบล็อกและความล้มเหลวของการทำซีเรียลไลซ์เซชั่น (ในรูปแบบของ deadlocks)
การเปิดเผยอย่างเต็มรูปแบบ: ฉันทำงานกับ Dan Ports ของ MIT เพื่อเพิ่มธุรกรรมที่ทำให้เป็นอนุกรมได้อย่างแท้จริงใน PostgreSQL เวอร์ชัน 9.1 โดยใช้เทคนิคใหม่ที่เรียกว่า Serializable Snapshot Isolation