08 · ฐานข้อมูล
ชั้นนี้เปลี่ยนพื้นที่เก็บข้อมูล (storage) ให้กลายเป็นความจำ — คั่นระหว่างความคงอยู่ของข้อมูล (persistence) แบบดิบด้านล่าง กับทุกแอปพลิเคชันด้านบนที่ต้องได้รับความจริง
อารยธรรมจดจำสิ่งต่างๆ ได้อย่างน่าเชื่อถือได้อย่างไร
ก่อนปี 1970 ถามคำถามที่คอมพิวเตอร์ไม่ได้ถูกสร้างมาให้ตอบ แปลว่าต้องเขียนโปรแกรมใหม่ และโปรแกรมนั้นต้องรู้ว่าคำตอบอยู่ตรงไหนในทางกายภาพ — ไฟล์ไหน เรียงลำดับแบบไหน ผูกกับ record อื่นด้วย pointer ตัวไหน จัดที่เก็บข้อมูลใหม่เพื่อให้รายงานหนึ่งเร็วขึ้น ทุกโปรแกรมที่แตะ record เหล่านั้นพังหมด ธุรกิจสะสมข้อมูลเร็วกว่าที่จะหาโปรแกรมเมอร์มาไล่ตามมันไปทั่วดิสก์ได้ทัน
นักคณิตศาสตร์ของ IBM ที่ San Jose Research Laboratory ตีพิมพ์เปเปอร์ที่ประโยคแรกคือคำประกาศอิสรภาพ: "ผู้ใช้ธนาคารข้อมูลขนาดใหญ่ในอนาคตต้องได้รับการปกป้องจากการต้องรู้ว่าข้อมูลถูกจัดระเบียบอย่างไรในเครื่อง (internal representation)" ("Future users of large data banks must be protected from having to know how the data is organized in the machine (the internal representation)") (Codd, CACM 13(6), 1970) Edgar Codd เสนอให้มองข้อมูลเป็น relations — เซตทางคณิตศาสตร์ของ tuple ไม่มีลำดับ ไม่มี pointer ไม่มีร่องรอยทางกายภาพของดิสก์เหลืออยู่เลย ผู้ใช้เห็นตาราง ส่วนตารางประกอบขึ้นจากอะไรไม่ใช่เรื่องของใครนอกจากระบบเอง
นามธรรม (abstraction) ที่ชั้นนี้ขายคือสิ่งนั้น และชื่อของมันคือ data independence ทุกอย่างที่เหลือในบทนี้มีอยู่เพื่อทำให้มันมีต้นทุนที่จ่ายไหว
ราคาของมันสูง เพราะคำถามที่เขียนเทียบกับตารางในอุดมคติไม่ได้บอกแผนการทำงานอะไรกับเครื่องเลย Codd เห็นผลที่ตามมาและพูดไว้ชัดว่า พลังของภาษาคิวรี (query) แบบนี้ "อยู่ที่ความสามารถในการบรรยาย (ไม่ใช่ความสามารถในการคำนวณ)" — คุณบรรยายคำตอบที่ต้องการ ไม่ใช่เส้นทางไปหามัน เส้นทางนั้นยังต้องมีใครสักคนจัดหาให้อยู่ดี คนนั้นกลายเป็น query optimizer เทคนิคที่ทำให้มันทำงานได้ตีพิมพ์โดยกลุ่มของ Pat Selinger ในปี 1979 จากต้นแบบ System R ของ IBM: ไล่ดูเส้นทางการเข้าถึงข้อมูลที่เป็นไปได้ ประเมินต้นทุนของแต่ละเส้นทางจากสถิติของข้อมูล เลือกเส้นทางที่ถูกที่สุด (Selinger et al., SIGMOD 1979) ไอเดียที่ดูไม่หวือหวา แต่ผลของมันใหญ่ — นักวิเคราะห์ยุคนี้เขียน SQL เก้าบรรทัดบนข้อมูลพันล้านแถวแล้วได้คำตอบ ในขณะที่การไล่ค้นด้วยมือแบบเทียบเท่ากันกินเวลาเป็นสัปดาห์และยังผิด System R ให้กำเนิดภาษาด้วย: SEQUEL ของ Donald Chamberlin กับ Raymond Boyce ในปี 1974 (SIGFIDET workshop) ภายหลังเปลี่ยนชื่อเป็น SQL เพราะบริษัทอื่นถือเครื่องหมายการค้าของคำนั้นไปก่อน
สิ่งที่สองที่ชั้นนี้ซ่อนไว้คือ ความล้มเหลว (failure) ไฟดับกลางคันขณะเขียนข้อมูล เสมียนสองคนขายที่นั่งเดียวกัน ดิสก์คืนหน้าข้อมูลของวันอังคารที่แล้วกลับมา สิ่งที่ยื่นให้แทนคือ ทรานแซกชัน (transaction): กลุ่มของการปฏิบัติการที่เกิดขึ้นทั้งหมดหรือไม่เกิดเลย ทำงานราวกับไม่มีใครอื่นทำงานอยู่พร้อมกัน และเมื่อยืนยันแล้วไม่มีวันสูญหาย Jim Gray วางการรับประกันเหล่านี้ไว้ในปี 1981 (The Transaction Concept, VLDB) ส่วน Theo Härder กับ Andreas Reuter ตั้งชื่อย่อที่ทุกคนท่องกันจนถึงวันนี้ — atomicity, consistency, isolation, durability — ในงานสำรวจปี 1983 ที่ยกเครดิตเนื้อหาให้ Gray (ACM Computing Surveys 15(4)) ทรานแซกชันคืออะไรกันแน่: ไม่ใช่กลไกหลีกเลี่ยงความล้มเหลว แต่เป็น สัญญาว่าความล้มเหลวได้รับอนุญาตให้มีหน้าตาแบบไหนเมื่อมองจากด้านบน กลไกด้านล่างพังอยู่ตลอดเวลา ผิว (surface) ที่มันยื่นให้ยอมรับผลลัพธ์แค่สองแบบ
กลไกที่ส่งมอบสัญญานั้นคือ log และเป็นไอเดียที่เข้าใจยากที่สุดในชั้นนี้ ความทนทาน (durability) ไม่ได้มาจากการเขียนข้อมูลอย่างระมัดระวัง แต่มาจากการเขียน เจตนา ก่อน เรียงเป็นลำดับ ลงไฟล์ที่มีแต่การต่อท้าย (append) เท่านั้น ค่อยไปแตะหน้าข้อมูลจริงเมื่อไหร่ก็ได้ที่สะดวก ถ้าเครื่องตาย การกู้คืนอ่าน log แล้วเล่นประวัติศาสตร์ซ้ำ: ทำสิ่งที่ commit แล้วซ้ำอีกครั้ง (redo) ย้อนสิ่งที่ยังไม่ commit กลับ (undo) แนวทางมาตรฐานคือ ARIES (Mohan et al., ACM TODS 17(1), 1992) และแพตเทิร์นนี้หลุดออกจากฐานข้อมูลไปนานแล้ว — filesystem ทำ journal, message queue ก็คือ log ที่สวมหน้ากากคนละแบบ และการทำสำเนา (replication) ในบทที่ 10 ก็คือเครื่องหนึ่งอ่าน log ของอีกเครื่องหนึ่ง หัวใจจริงของฐานข้อมูลไม่ใช่ตาราง แต่คือบันทึกแบบต่อท้ายอย่างเดียว (append-only) ของสิ่งที่มันถูกสั่งให้ทำ
จุดเดียวที่โลกทางกายภาพได้รับอนุญาตให้โผล่ผ่านมาคือ ดัชนี (index) และฮาร์ดแวร์ที่อยู่สองชั้นด้านล่างเป็นตัวกำหนดรูปทรงของมัน B-tree ของ Rudolf Bayer กับ Edward McCreight จากรายงานของ Boeing ปี 1970 และ Acta Informatica ปี 1972 (Bayer & McCreight) กว้างและตื้นโดยตั้งใจ — แต่ละโหนดมีลูกได้เป็นร้อย หนึ่งโหนดเต็มพอดีหนึ่งหน้าดิสก์ การค้นหาท่ามกลางข้อมูลนับพันล้านแถวจึงเสียแค่สามหรือสี่ครั้งในการดึงข้อมูล แทนที่จะเป็นสามสิบครั้ง นี่คือข้อแลกเปลี่ยน (trade-off) ของบทที่ 02 ที่จ่ายกันในระดับอุตสาหกรรม: สร้างโครงสร้างไว้ตอนนี้ ทั้งพื้นที่และต้นทุนการเขียน เพื่อให้คำถามในอนาคตถูกลง และนี่คือจุดที่ abstraction รั่ว คิวรี (query) สองตัวที่เหมือนกันทุกอย่างในเชิงตรรกะ ใช้เวลาต่างกันได้ถึงสี่ระดับขนาด (order of magnitude) เพราะตัวหนึ่งมี index อีกตัวไม่มี — ผิว (surface) บอกแค่ อะไร แต่บิลคิดเป็น อย่างไร
คนในเรื่องนี้คุ้มค่าที่จะแวะดูสักครู่ นายจ้างของ Codd เองช้าที่จะสร้างสิ่งที่เขาบรรยายไว้ เพราะมีเงินลงทุนก้อนใหญ่ที่ยังทำกำไรอยู่ในระบบ hierarchical รุ่นเก่าที่มันจะเข้ามาแทนที่ (Wade & Chamberlin, IEEE Annals, 2012) แบบจำลองเชิงสัมพันธ์ (relational model) ไปถึงมือลูกค้าส่วนหนึ่งผ่านคนอื่น และ Codd ได้รับรางวัล Turing Award ในปี 1981 จากเปเปอร์ที่บริษัทของเขาเองเถียงค้านมานานนับสิบปี (ACM)
เรื่องเดินมาถึงช่วงที่สัญญานั้นคลายตัว ราวปี 2006–2007 ระบบสองตัวที่สร้างมาเพื่อสเกลที่สัญญาเชิงสัมพันธ์ไปไม่ถึงถูกตีพิมพ์ — Bigtable ของ Google (OSDI 2006) กับ Dynamo ของ Amazon (SOSP 2007) — และในเดือนมิถุนายน 2009 งาน meetup ที่ San Francisco ตั้งชื่อให้ขบวนการนี้ ชื่อที่มันจะต้องมานั่งเสียใจไปอีกสิบปี: NoSQL ข้อแลกเปลี่ยนถูกพูดออกมาตรงๆ: ยอมไม่มี join ยอมไม่มีทรานแซกชัน (transaction) ที่แข็งแรงข้ามเครื่อง แล้วเอาสิ่งที่ยอมแลกไปซื้อสเกลแนวนอน สิ่งที่เกิดขึ้นต่อมาคือส่วนที่น่าสนใจ พอขายการรับประกันเหล่านั้นไปแล้ว วงการก็ค้นพบว่าต้องเขียนโค้ดในแอปพลิเคชันมากแค่ไหนถึงจะปลอมมันขึ้นมาใหม่ได้ และระบบพวกนี้ส่วนใหญ่ก็งอกทรานแซกชันกับภาษาคิวรีกลับคืนมาตั้งแต่นั้น บทที่ 10 อธิบายว่าทำไมการรับประกันเหล่านี้ถึงแพงตั้งแต่แรก — และทำไมมันจะไม่มีวันฟรี เมื่อข้อมูลอยู่บนเครื่องมากกว่าหนึ่งเครื่อง
เชื่อมโยง
ด้านล่าง: บทที่ 04 ให้ลำดับชั้นหน่วยความจำ (memory hierarchy) ที่กำหนดรูปทรงของ B-tree ส่วนบทที่ 05 ให้ไฟล์ โพรเซส (process) และปัญหา crash consistency มาในรูปดิบๆ — ฐานข้อมูลคือสิ่งที่เกิดขึ้นเมื่อโปรแกรมหนึ่งรับหน้าที่เหล่านั้นมาจากระบบปฏิบัติการแล้วทำมันอย่างถูกต้องจริงจัง บทที่ 02 เป็นเจ้าของโครงสร้างข้อมูล บทที่ 03 อธิบายว่าทำไมคอลัมน์ที่บีบอัดแล้วกับหน้าข้อมูลที่เข้ารหัสแล้วถึงทำงานได้ตั้งแต่แรก ด้านบน: บทที่ 07 อยู่ที่นี่ถาวร เพราะสคีมา (schema) คือสิ่งที่แก้ยากที่สุดในระบบใดๆ ก็ตาม บทที่ 09 พา client ข้ามเครือข่ายไป บทที่ 10 ถามว่าการรับประกันเหล่านี้เหลืออะไรอยู่บ้าง เมื่อเครื่องจริงๆ แล้วคือเครื่องหลายเครื่อง
คำถามที่ยังเปิดอยู่
แบบจำลองเชิงสัมพันธ์ (relational model) เป็นชั้นถาวร หรือเป็นแค่จุดสูงสุดเฉพาะที่ (local maximum) ที่อยู่มาได้ห้าสิบปี ผู้วิจารณ์ประกาศว่ามันล้าสมัยมาแล้วสองครั้ง — เรื่อง object ในทศวรรษ 1990 เรื่องสเกลในทศวรรษ 2000 — และมันกลืนคู่แข่งเข้าไปได้ทั้งสองครั้ง ข้อสอง: query optimizer ตอนนี้เป็นส่วนประกอบที่คาดเดาไม่ได้มากที่สุดในระบบส่วนใหญ่ เลือกผิดพลาดร้ายแรงได้จากสถิติที่ล้าสมัย optimizer ที่เรียนรู้ได้ (learned optimizer) เป็นแนวรบวิจัยที่กำลังคึกคัก แต่โมเดลที่ประเมินผิดดีบั๊กยากกว่าสูตรที่ประเมินผิด ข้อสาม และยังไม่ลงตัวที่สุด: log คือส่วนประกอบเดียวที่ระบบข้อมูลสมัยใหม่ทุกตัวมาบรรจบกัน ถ้า storage, queue, replication และ stream processing ล้วนเป็น log อยู่ข้างใต้ "ฐานข้อมูล" ยังเป็นหน่วยคิดที่ถูกต้องอยู่หรือเปล่า หรือว่า log ต่างหากที่เป็นชั้น ส่วนฐานข้อมูลเป็นแค่มุมมองหนึ่งที่สร้างซ้อนอยู่ข้างบน
อ่านต่อ
- E. F. Codd, "A Relational Model of Data for Large Shared Data Banks," Communications of the ACM 13, no. 6 (1970): 377–387 — สิบสองหน้าที่จัดระเบียบทั้งอุตสาหกรรมใหม่; ACM DL.
- Peter Bailis, Joseph M. Hellerstein & Michael Stonebraker, eds., Readings in Database Systems, 5th ed., 2015 — คัมภีร์ที่วงการคัดสรรเอง พร้อมคำอธิบายจากบรรณาธิการ; อ่านฟรีที่ redbook.io.
- Abraham Silberschatz, Henry F. Korth & S. Sudarshan, Database System Concepts, 7th ed., McGraw-Hill, 2019 — ตำราเรียนมาตรฐาน ถ้าต้องการกลไกแบบเต็มรูปแบบ.