SQLite3 จัดการการเข้าถึงพร้อมกันอย่างปลอดภัยโดยหลายกระบวนการอ่าน / เขียนจากฐานข้อมูลเดียวกันหรือไม่ มีข้อยกเว้นสำหรับแพลตฟอร์มใดบ้าง
SQLite3 จัดการการเข้าถึงพร้อมกันอย่างปลอดภัยโดยหลายกระบวนการอ่าน / เขียนจากฐานข้อมูลเดียวกันหรือไม่ มีข้อยกเว้นสำหรับแพลตฟอร์มใดบ้าง
คำตอบ:
หากการเข้าถึงที่เกิดขึ้นพร้อมกันส่วนใหญ่เป็นการอ่าน (เช่น SELECT) SQLite สามารถจัดการกับมันได้เป็นอย่างดี แต่ถ้าคุณเริ่มเขียนพร้อมกันการแย่งชิงล็อคอาจกลายเป็นปัญหา จำนวนมากจะขึ้นอยู่กับความรวดเร็วของระบบไฟล์ของคุณเนื่องจากตัวโปรแกรม SQLite นั้นเร็วมากและมีการปรับแต่งที่ชาญฉลาดเพื่อลดความขัดแย้ง โดยเฉพาะ SQLite 3
สำหรับแอพพลิเคชันเดสก์ท็อป / แล็ปท็อป / แท็บเล็ต / โทรศัพท์ส่วนใหญ่ SQLite นั้นเร็วพอเนื่องจากไม่มีการทำงานพร้อมกัน (Firefox ใช้ SQLite อย่างกว้างขวางสำหรับบุ๊กมาร์กประวัติ ฯลฯ )
สำหรับแอปพลิเคชั่นเซิร์ฟเวอร์บางคนกล่าวเมื่อไม่นานมานี้ว่ามีการดูเพจน้อยกว่า 100K ต่อวันสามารถจัดการได้อย่างสมบูรณ์แบบโดยฐานข้อมูล SQLite ในสถานการณ์ทั่วไป (เช่นบล็อกฟอรัม) และฉันยังไม่เห็นหลักฐานใด ๆ ในความเป็นจริงด้วยดิสก์และตัวประมวลผลที่ทันสมัย 95% ของเว็บไซต์และบริการเว็บจะทำงานได้ดีกับ SQLite
ถ้าคุณอยากอ่านได้อย่างรวดเร็วเข้าถึง / เขียนใช้ฐานข้อมูล SQLite ในหน่วยความจำ RAM มีขนาดของคำสั่งเร็วกว่าดิสก์หลายเท่า
ใช่ SQLite จัดการกับการเกิดพร้อมกันได้ดี แต่มันไม่ได้ดีที่สุดจากมุมมองประสิทธิภาพ จากสิ่งที่ฉันสามารถบอกได้ไม่มีข้อยกเว้นใด ๆ รายละเอียดอยู่บนเว็บไซต์ของ SQLite: https://www.sqlite.org/lockingv3.html
คำสั่งนี้มีความน่าสนใจ: "โมดูลเพจเจอร์ทำให้แน่ใจว่าการเปลี่ยนแปลงเกิดขึ้นทั้งหมดในครั้งเดียวซึ่งการเปลี่ยนแปลงทั้งหมดเกิดขึ้นหรือไม่มีสิ่งใดเกิดขึ้นกระบวนการนั้นสองกระบวนการขึ้นไปไม่พยายามเข้าถึงฐานข้อมูลด้วยวิธีที่เข้ากันไม่ได้ในเวลาเดียวกัน"
ใช่แล้ว. ลองคิดดูว่าทำไม
การเปลี่ยนแปลงทั้งหมดภายในธุรกรรมเดียวใน SQLite อาจเกิดขึ้นอย่างสมบูรณ์หรือไม่เลย
สนับสนุนกรดดังกล่าวเช่นเดียวกับการเกิดขึ้นพร้อมกันในการอ่าน / เขียนไว้ใน 2 วิธี - โดยใช้สิ่งที่เรียกว่าบันทึก (ช่วยให้เรียกว่า“ วิธีการแบบเก่า ”) หรือการเข้าสู่ระบบเขียนล่วงหน้า (ช่วยให้เรียกว่า“ วิธีการใหม่ ”)
ในโหมดนี้ SQLite ใช้ระดับฐานข้อมูล การล็อค นี่คือจุดสำคัญที่จะเข้าใจ
ซึ่งหมายความว่าเมื่อใดก็ตามที่จำเป็นต้องอ่าน / เขียนสิ่งที่มันได้มาล็อคในไฟล์ฐานข้อมูลทั้งหมด ผู้อ่านหลายคนสามารถอยู่ร่วมกันและอ่านบางอย่างในแบบคู่ขนาน
ในระหว่างการเขียนจะทำให้แน่ใจว่าได้รับการล็อคแบบเอกสิทธิ์เฉพาะบุคคลและไม่มีกระบวนการอื่นที่จะอ่าน / เขียนพร้อมกันและดังนั้นการเขียนจึงปลอดภัย
นี่คือเหตุผลที่นี่พวกเขากำลังจะบอกว่าการดำเนินการ SQLite serializableการทำธุรกรรม
เนื่องจากมันต้องการล็อคฐานข้อมูลทั้งหมดทุกครั้งและทุกคนรอกระบวนการจัดการการเขียนภาวะพร้อมกันและการอ่าน / อ่านพร้อมกันนั้นมีประสิทธิภาพต่ำ
ก่อนที่จะเขียนบางสิ่งลงในไฟล์ฐานข้อมูล SQLite ก่อนอื่นจะบันทึก chunk ที่จะเปลี่ยนในไฟล์ชั่วคราว หากมีปัญหาเกิดขึ้นในระหว่างการเขียนลงในไฟล์ฐานข้อมูลมันจะรับไฟล์ชั่วคราวนี้และกลับการเปลี่ยนแปลงจากมัน
ในกรณีนี้การเขียนทั้งหมดจะถูกผนวกเข้ากับไฟล์ชั่วคราว ( บันทึกการเขียนล่วงหน้า ) และไฟล์นี้จะถูกผสานเป็นระยะกับฐานข้อมูลดั้งเดิม เมื่อ SQLite กำลังค้นหาบางอย่างก่อนอื่นให้ตรวจสอบไฟล์ชั่วคราวนี้และหากไม่พบสิ่งใดให้ดำเนินการต่อด้วยไฟล์ฐานข้อมูลหลัก
ดังนั้นผู้อ่านจะไม่แข่งขันกับนักเขียนและประสิทธิภาพจะดีกว่าเมื่อเทียบกับ Old Way
SQlite หนักขึ้นอยู่กับฟังก์ชั่นการล็อคระบบไฟล์พื้นฐานดังนั้นจึงควรใช้ด้วยความระมัดระวังและรายละเอียดเพิ่มเติมที่นี่
คุณยังมีแนวโน้มที่จะพบกับข้อผิดพลาดที่ถูกล็อคโดยเฉพาะอย่างยิ่งในโหมด journaled ดังนั้นแอปของคุณจะต้องได้รับการออกแบบโดยคำนึงถึงข้อผิดพลาดนี้
ดูเหมือนว่าไม่มีใครพูดถึงโหมด WAL (Write Ahead Log) ตรวจสอบให้แน่ใจว่าธุรกรรมต่าง ๆ ได้รับการจัดการอย่างถูกต้องและเมื่อตั้งโหมด WAL ไว้ไม่จำเป็นต้องเก็บฐานข้อมูลไว้ในขณะที่ผู้คนกำลังอ่านสิ่งต่าง ๆ ในขณะที่มีการอัพเดทเกิดขึ้น
ปัญหาเดียวคือในบางจุด WAL จำเป็นต้องรวมเข้ากับฐานข้อมูลหลักอีกครั้งและจะทำเช่นนี้เมื่อการเชื่อมต่อล่าสุดไปยังฐานข้อมูลปิด ด้วยไซต์ที่ยุ่งมากคุณอาจพบว่าการปิดการเชื่อมต่อทั้งหมดใช้เวลาสองสามวินาที แต่การเข้าชม 100K ต่อวันไม่น่าจะมีปัญหา
database is locked
ข้อผิดพลาดที่จะเพิ่มขึ้นโดยนักเขียน
ในปี 2019 มีตัวเลือกการเขียนพร้อมกันใหม่สองตัวที่ยังไม่ออก แต่มีให้ในสาขาแยก
ข้อดีของโหมดเจอร์นัลนี้ในโหมด "wal" ปกติคือผู้เขียนอาจทำการเขียนต่อไปยังไฟล์ wal หนึ่งไฟล์ในขณะที่โหมดอื่นถูกตรวจสอบ
BEGIN CONCURRENT - ลิงค์ไปยังเอกสารรายละเอียด
การปรับปรุง BEGIN CONCURRENT ช่วยให้นักเขียนหลายคนสามารถประมวลผลธุรกรรมการเขียนพร้อมกันได้หากฐานข้อมูลอยู่ในโหมด "wal" หรือ "wal2" แม้ว่าระบบจะยังคงซีเรียลคำสั่ง COMMIT
เมื่อการเขียนธุรกรรมถูกเปิดด้วย "BEGIN CONCURRENT" การล็อกฐานข้อมูลจะถูกเลื่อนออกไปจนกว่าจะมีการเรียกใช้ COMMIT ซึ่งหมายความว่าจำนวนธุรกรรมที่เริ่มต้นด้วย BEGIN CONCURRENT อาจดำเนินการพร้อมกัน ระบบใช้การล็อกระดับหน้าในแง่ดีเพื่อป้องกันการทำธุรกรรมที่เกิดขึ้นพร้อมกันไม่ให้เกิดความขัดแย้ง
ร่วมกันพวกเขามีอยู่ในเริ่มต้นพร้อมกัน-wal2หรือในแต่ละเองแยกต่างหากสาขา
begin concurrent
สิ่งนั้น
SQLite มีล็อกผู้อ่าน - ผู้เขียนในระดับฐานข้อมูล การเชื่อมต่อที่หลากหลาย (อาจเป็นเจ้าของกระบวนการที่แตกต่างกัน) สามารถอ่านข้อมูลจากฐานข้อมูลเดียวกันในเวลาเดียวกัน แต่มีเพียงคนเดียวเท่านั้นที่สามารถเขียนไปยังฐานข้อมูล
SQLite รองรับจำนวนผู้อ่านพร้อมกันไม่ จำกัด แต่จะอนุญาตให้ผู้เขียนหนึ่งคนในเวลาใดก็ได้ สำหรับหลาย ๆ สถานการณ์นี่ไม่ใช่ปัญหา คิวนักเขียน แต่ละแอปพลิเคชันทำงานกับฐานข้อมูลได้อย่างรวดเร็วและเดินหน้าต่อไปและไม่มีการล็อคเป็นเวลานานกว่าสองสามมิลลิวินาที แต่มีบางแอพพลิเคชั่นที่ต้องการการทำงานพร้อมกันมากกว่าเดิมและแอพพลิเคชั่นเหล่านั้นอาจต้องหาทางออกที่แตกต่างกัน - การใช้ที่เหมาะสมสำหรับ SQLite @ SQLite.org
ล็อคผู้อ่าน - ผู้เขียนเปิดใช้งานการประมวลผลธุรกรรมที่เป็นอิสระและถูกนำไปใช้โดยใช้การล็อกแบบเอกสิทธิ์
การล็อคแบบเอกสิทธิ์เฉพาะบุคคลจะต้องได้รับก่อนที่การเชื่อมต่อทำการดำเนินการเขียนในฐานข้อมูล หลังจากได้รับการล็อคแบบเอกสิทธิ์เฉพาะบุคคลทั้งการอ่านและการเขียนจากการเชื่อมต่ออื่น ๆ จะถูกบล็อกจนกว่าการล็อกจะถูกปล่อยอีกครั้ง
SQLite มีตารางล็อคที่ช่วยล็อกฐานข้อมูลให้ช้าที่สุดเท่าที่จะเป็นไปได้ในระหว่างการดำเนินการเขียนเพื่อให้แน่ใจว่ามีการทำงานพร้อมกันสูงสุด
สถานะเริ่มต้นถูกปลดล็อคและในสถานะนี้การเชื่อมต่อยังไม่สามารถเข้าถึงฐานข้อมูลได้ เมื่อกระบวนการเชื่อมต่อกับฐานข้อมูลและแม้แต่ธุรกรรมเริ่มต้นด้วย BEGIN การเชื่อมต่อจะยังคงอยู่ในสถานะปลดล็อค
หลังจากสถานะ UNLOCKED สถานะถัดไปคือสถานะ SHARED เพื่อให้สามารถอ่าน (ไม่เขียน) ข้อมูลจากฐานข้อมูลการเชื่อมต่อจะต้องเข้าสู่สถานะ SHARED ก่อนโดยรับล็อค SHARED การเชื่อมต่อที่หลากหลายสามารถรับและบำรุงรักษาการล็อค SHARED ในเวลาเดียวกันดังนั้นการเชื่อมต่อหลายรายการสามารถอ่านข้อมูลจากฐานข้อมูลเดียวกันในเวลาเดียวกัน แต่ตราบใดที่การล็อค SHARED เพียงอันเดียวยังคงไม่ได้เผยแพร่การเชื่อมต่อจะไม่สามารถเขียนไปยังฐานข้อมูลได้สำเร็จ
หากการเชื่อมต่อต้องการที่จะเขียนไปยังฐานข้อมูลนั้นจะต้องได้รับล็อค RESERVED ก่อน
ล็อค RESERVED เดียวเท่านั้นที่สามารถใช้งานได้ในคราวเดียวแม้ว่าการล็อค SHARED หลายครั้งสามารถอยู่ร่วมกันได้ด้วยการล็อค RESERVED เดียว RESERVED นั้นแตกต่างจาก PENDING ในล็อค SHARED ใหม่ที่สามารถรับได้ในขณะที่มีล็อค RESERVED - การล็อคไฟล์และการทำงานพร้อมกันใน SQLite เวอร์ชัน 3 @ SQLite.org
เมื่อการเชื่อมต่อได้รับการล็อค RESERVED การเชื่อมต่อสามารถเริ่มต้นการประมวลผลการแก้ไขฐานข้อมูลแม้ว่าการแก้ไขเหล่านี้สามารถทำได้ในบัฟเฟอร์เท่านั้นแทนที่จะเขียนลงดิสก์จริง การปรับเปลี่ยนที่ทำกับเนื้อหาที่อ่านได้จะถูกบันทึกในบัฟเฟอร์หน่วยความจำ เมื่อการเชื่อมต่อต้องการส่งการปรับเปลี่ยน (หรือการทำธุรกรรม) จำเป็นต้องอัพเกรดล็อค RESERVED เป็นล็อค EXCLUSIVE ในการรับล็อคคุณต้องยกล็อคไปที่ล็อค PENDING ก่อน
การล็อคที่รออยู่หมายความว่ากระบวนการที่ถือล็อคต้องการเขียนไปยังฐานข้อมูลโดยเร็วที่สุดและกำลังรอการล็อค SHARED ปัจจุบันทั้งหมดเพื่อล้างเพื่อให้สามารถล็อค EXCLUSIVE ได้ ไม่อนุญาตให้ใช้การล็อก SHARED ใหม่กับฐานข้อมูลหากการล็อก PENDING ทำงานอยู่แม้ว่าการล็อก SHARED ที่มีอยู่จะได้รับอนุญาตให้ดำเนินการต่อได้
จำเป็นต้องใช้การล็อค EXCLUSIVE เพื่อเขียนไปยังไฟล์ฐานข้อมูล อนุญาตให้ล็อกเอกสิทธิ์ EXCLUSIVE เดียวเท่านั้นในไฟล์และห้ามมิให้ล็อคอื่นใดที่อยู่ร่วมกับ EXCLUSIVE lock เพื่อให้เกิดการทำงานพร้อมกันสูงสุด SQLite จะทำงานเพื่อลดระยะเวลาในการล็อค EXCLUSIVE ให้น้อยที่สุด - การล็อคไฟล์และการทำงานพร้อมกันใน SQLite เวอร์ชัน 3 @ SQLite.org
ดังนั้นคุณอาจบอกว่า SQLite จัดการการเข้าถึงที่เกิดขึ้นพร้อมกันได้อย่างปลอดภัยโดยกระบวนการหลายกระบวนการที่เขียนไปยังฐานข้อมูลเดียวกันเพราะมันไม่รองรับ! คุณจะได้รับSQLITE_BUSY
หรือSQLITE_LOCKED
สำหรับนักเขียนคนที่สองเมื่อพบข้อ จำกัด การลองใหม่
เธรดนี้เก่า แต่ฉันคิดว่ามันจะเป็นการดีที่จะแบ่งปันผลการทดสอบของฉันใน sqlite: ฉันรันโปรแกรมอินสแตนซ์ของ python 2 โปรแกรม (กระบวนการที่แตกต่างกันในโปรแกรมเดียวกัน) ดำเนินการคำสั่ง SELECT และ UPDATE sql คำสั่ง 10 วินาทีในการล็อคและผลลัพธ์ก็น่าผิดหวัง ทุกตัวอย่างทำใน 10000 step loop
แม้ว่า sqlite จะได้รับการล็อคแบบเอกสิทธิ์เฉพาะบุคคลในการทำธุรกรรมจำนวนรอบของการดำเนินการจริง ๆ นั้นไม่เท่ากับ 20,000 แต่น้อยกว่า (จำนวนการวนซ้ำทั้งหมดบนตัวนับเดียวนับสำหรับกระบวนการทั้งสอง) โปรแกรม Python แทบจะไม่มีข้อยกเว้นใด ๆ เลย (เพียงครั้งเดียวในระหว่างการเลือกสำหรับการประมวลผล 20 ครั้ง) การแก้ไข sqlite ในขณะทำการทดสอบคือ 3.6.20 และ python v3.3 CentOS 6.5 ในความคิดของฉันมันจะดีกว่าที่จะหาผลิตภัณฑ์ที่น่าเชื่อถือมากขึ้นสำหรับงานประเภทนี้หรือ จำกัด การเขียนไปยัง sqlite เพื่อกระบวนการที่ไม่ซ้ำกัน / ด้าย
with con
เพียงพอ