เวอร์ชันควบคุมเนื้อหาของฐานข้อมูล


16

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

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

ฉันสามารถคิดถึงวิธีการติดตามการเปลี่ยนแปลงของตัวเองได้บ้าง แต่พวกเขาทั้งหมดดูค่อนข้างหยาบ:

  • บันทึกทั้งแถวในการเปลี่ยนแปลงแต่ละรายการเชื่อมโยงแถวกลับไปยังรหัสแหล่งที่มาด้วยคีย์หลัก การเปลี่ยนแปลงเล็ก ๆ น้อย ๆ จำนวนมากอาจทำให้โต๊ะโตมาก
  • บันทึกก่อน / หลัง / ผู้ใช้ / การประทับเวลาสำหรับการเปลี่ยนแปลงแต่ละรายการด้วยชื่อคอลัมน์เพื่อเชื่อมโยงการเปลี่ยนแปลงกลับไปยังคอลัมน์ที่เกี่ยวข้อง
  • บันทึกก่อน / หลัง / user / timestamp ด้วยตารางสำหรับแต่ละคอลัมน์ (อาจส่งผลให้มีตารางมากเกินไป)
  • บันทึก diffs / user / timestamp สำหรับการเปลี่ยนแปลงแต่ละรายการด้วยคอลัมน์ (ซึ่งหมายความว่าคุณต้องเดินผ่านประวัติการเปลี่ยนแปลงทั้งหมดเพื่อย้อนกลับไปยังวันที่แน่นอน)

อะไรคือวิธีที่ดีที่สุดที่นี่? ดูเหมือนว่าฉันจะพลิกโฉมฐานข้อมูลโค้ดของคนอื่น (ดีกว่า)


คะแนนโบนัสสำหรับ PostgreSQL


คำถามนี้ถูกพูดถึงแล้วใน SO: stackoverflow.com/questions/3874199/… . Google สำหรับ "บันทึกประวัติฐานข้อมูล" และคุณจะพบบทความเพิ่มเติม
Doc Brown

1
ฟังดูเหมือนเป็นตัวเลือกที่ดีที่สุดสำหรับการจัดหากิจกรรม
James

ทำไมไม่ใช้บันทึกธุรกรรมของ SQL-Server เพื่อทำการหลอกลวง?
โทมัสขยะ

คำตอบ:


11

เทคนิคที่ฉันใช้ตามปกติคือบันทึกเร็กคอร์ดที่สมบูรณ์ด้วยฟิลด์ end_timestamp มีกฎทางธุรกิจที่มีเพียงแถวเดียวเท่านั้นที่สามารถมี null end_timestamp และนี่เป็นเนื้อหาที่ใช้งานอยู่ในปัจจุบัน

หากคุณใช้ระบบนี้ฉันขอแนะนำให้คุณเพิ่มดัชนีหรือข้อ จำกัด เพื่อบังคับใช้กฎ Oracle เป็นสิ่งที่ง่ายเนื่องจากดัชนีที่ไม่ซ้ำใครสามารถมีได้เพียงค่าเดียวเท่านั้น ฐานข้อมูลอื่นอาจมีปัญหามากกว่านี้ มีฐานข้อมูลบังคับใช้กฎจะรักษารหัสของคุณซื่อสัตย์

คุณค่อนข้างถูกต้องว่าการเปลี่ยนแปลงเล็ก ๆ จำนวนมากจะสร้างการขยายตัว แต่คุณต้องแลกเปลี่ยนสิ่งนี้กับรหัสและการรายงานที่ไม่ซับซ้อน


โปรดทราบว่าเอ็นจิ้นฐานข้อมูลอื่นอาจทำงานแตกต่างกันเช่น MySQL อนุญาตให้ค่า NULL หลายค่าในคอลัมน์ที่มีดัชนีไม่ซ้ำกัน สิ่งนี้ทำให้ข้อ จำกัด นี้ยากกว่าในการบังคับใช้
qbd

การใช้การประทับเวลาจริงนั้นไม่ปลอดภัย แต่ฐานข้อมูล MVCC บางตัวทำงานภายในโดยการจัดเก็บหมายเลขซีเรียลการทำธุรกรรมขั้นต่ำและสูงสุดพร้อมกับสิ่งอันดับ
user2313838

"สิ่งนี้เป็นเรื่องง่ายสำหรับ Oracle เนื่องจากดัชนีเฉพาะสามารถมีค่าได้เพียงค่าเดียวเท่านั้น" ไม่ถูกต้อง. Oracle ไม่ได้รวมค่า Null ในดัชนีเลย ไม่มีข้อ จำกัด เกี่ยวกับจำนวนของโมฆะในคอลัมน์ที่มีดัชนีที่ไม่ซ้ำกัน
Gerrat

@Gerrat เป็นเวลาหลายปีแล้วที่ฉันออกแบบฐานข้อมูลที่มีข้อกำหนดนี้และฉันไม่สามารถเข้าถึงฐานข้อมูลนั้นได้อีกต่อไป คุณถูกต้องที่ดัชนีเฉพาะมาตรฐานสามารถรองรับหลายค่าได้ แต่ฉันคิดว่าเราใช้ข้อ จำกัด ที่ไม่ซ้ำกันหรืออาจเป็นดัชนีที่ใช้งานได้
kiwiron

8

หมายเหตุว่าถ้าคุณใช้ Microsoft SQL Server, มีอยู่แล้วคุณลักษณะที่เรียกว่าจับเปลี่ยนข้อมูล คุณยังจะต้องเขียนรหัสเพื่อเข้าถึงการแก้ไขก่อนหน้าในภายหลัง (CDC สร้างมุมมองเฉพาะสำหรับเรื่องนั้น) แต่อย่างน้อยคุณไม่จำเป็นต้องเปลี่ยนสคีมาของตารางของคุณหรือใช้การติดตามการเปลี่ยนแปลงเอง

ภายใต้ประทุนสิ่งที่เกิดขึ้นคือ:

  • CDC สร้างตารางเพิ่มเติมที่มีการแก้ไข

  • ตารางดั้งเดิมของคุณถูกใช้เหมือนเดิมก่อนหน้านี้นั่นคือการปรับปรุงใด ๆ ที่ปรากฏในตารางนี้โดยตรง

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

ความจริงที่ว่าการเปลี่ยนแปลงถูกเก็บไว้ในตารางที่แตกต่างกันมีสองผลกระทบที่สำคัญ:

  • เลือกจากตารางต้นฉบับเร็วเท่าที่ไม่มี CDC หากฉันจำได้ดี CDC จะเกิดขึ้นหลังจากการอัปเดตดังนั้นการอัปเดตจึงรวดเร็วเท่า ๆ กัน (แม้ว่าฉันจะจำไม่ได้ว่า CDC จัดการความสอดคล้องของข้อมูลอย่างไร

  • การเปลี่ยนแปลงบางอย่างกับ schema ของตารางต้นฉบับนำไปสู่การลบ CDC ตัวอย่างเช่นหากคุณเพิ่มคอลัมน์ CDC จะไม่ทราบวิธีจัดการกับสิ่งนั้น ในทางกลับกันการเพิ่มดัชนีหรือข้อ จำกัด ควรจะดี ปัญหานี้จะกลายเป็นปัญหาได้อย่างรวดเร็วหากคุณเปิดใช้งาน CDC บนโต๊ะซึ่งอาจมีการเปลี่ยนแปลงบ่อยครั้ง อาจมีวิธีแก้ไขที่อนุญาตให้เปลี่ยนสกีมาโดยไม่สูญเสีย CDC แต่ฉันไม่ได้ค้นหามัน


6

แก้ปัญหา "ปรัชญา" และในรหัสก่อน จากนั้น "เจรจา" กับรหัสและฐานข้อมูลเพื่อให้มันเกิดขึ้น

ตัวอย่างเช่นหากคุณกำลังเกี่ยวข้องกับบทความทั่วไปแนวคิดเริ่มต้นสำหรับบทความอาจมีลักษณะเช่นนี้:

class Article {
  public Int32 Id;
  public String Body;
}

และในระดับพื้นฐานที่สุดถัดไปฉันต้องการเก็บรายการการแก้ไข:

class Article {
  public Int32 Id;
  public String Body;
  public List<String> Revisions;
}

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

class Revision {
  public Int32 Id;
  public Article ParentArticle;
  public DateTime Created;
  public String Body;
}

และ ... และเนื้อหาปัจจุบันของบทความไม่จำเป็นต้องแตกต่างจากฉบับแก้ไขล่าสุด:

class Article {
  public Int32 Id;
  public String Body {
    get {
      return (Revisions.OrderByDesc(r => r.Created))[0];
    }
    set {
      Revisions.Add(new Revision(value));
    }
  }
  public List<Revision> Revisions;
}

รายละเอียดบางอย่างขาดหายไป แต่มันก็แสดงให้เห็นว่าคุณอาจต้องการทั้งสองหน่วยงาน หนึ่งแสดงถึงบทความ (หรือส่วนหัวอื่น ๆ ประเภท) และอื่น ๆ เป็นรายการของการแก้ไข (การจัดกลุ่มสิ่งที่สาขาทำให้รู้สึก "ปรัชญา" ที่ดีในการจัดกลุ่ม) คุณไม่จำเป็นต้องมีข้อ จำกัด ของฐานข้อมูลพิเศษในตอนแรกเนื่องจากรหัสของคุณไม่สนใจเกี่ยวกับการแก้ไขใด ๆ ที่เกิดขึ้นในตัวเองซึ่งเป็นคุณสมบัติของบทความที่รู้เกี่ยวกับการแก้ไข

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

และคุณปล่อยให้ ORM จัดการกับรายละเอียดทางปรัชญาน้อยกว่า - หรือซ่อนไว้ในคลาสยูทิลิตี้ที่กำหนดเองหากคุณไม่ได้ใช้ ORM นอกกรอบ

มากหลังจากนั้นหลังจากที่คุณทำการทดสอบความเครียดคุณอาจคิดเกี่ยวกับการทำให้คุณสมบัติการแก้ไขแบบ lazy-load หรือการมีคุณลักษณะร่างกายของคุณ lazy-load เพียงการแก้ไขสูงสุด แต่โครงสร้างข้อมูลของคุณในกรณีนี้ไม่ควรเปลี่ยนแปลงเพื่อรองรับการปรับให้เหมาะสมเหล่านั้น


2

มีหน้าวิกิ PostgreSQL สำหรับทริกเกอร์การติดตามตรวจสอบซึ่งจะแนะนำวิธีการตั้งค่าบันทึกการตรวจสอบที่จะทำสิ่งที่คุณต้องการ

ติดตามข้อมูลต้นฉบับทั้งหมดของการเปลี่ยนแปลงตลอดจนรายการค่าใหม่สำหรับการอัปเดต (สำหรับแทรกและลบมีเพียงค่าเดียว) หากคุณต้องการกู้คืนเวอร์ชันเก่าคุณสามารถคว้าสำเนาของข้อมูลต้นฉบับจากบันทึกการตรวจสอบ โปรดทราบว่าหากข้อมูลของคุณเกี่ยวข้องกับกุญแจต่างประเทศระเบียนเหล่านั้นอาจต้องย้อนกลับเพื่อรักษาความสอดคล้อง

โดยทั่วไปหากแอปพลิเคชันฐานข้อมูลของคุณใช้เวลาส่วนใหญ่ไปกับข้อมูลปัจจุบันฉันคิดว่าคุณดีกว่าที่จะติดตามรุ่นอื่นในตารางแยกต่างหากจากข้อมูลปัจจุบัน สิ่งนี้จะทำให้ดัชนีตารางที่ใช้งานอยู่ของคุณจัดการได้ง่ายขึ้น

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


1

ทีนี้ฉันก็หายไปด้วยตัวเลือกที่ง่ายที่สุดทริกเกอร์ที่คัดลอกเวอร์ชันเก่าของแถวไปยังบันทึกประวัติต่อตาราง

หากฉันจบลงด้วยการขยายฐานข้อมูลมากเกินไปฉันสามารถดูว่าอาจยุบการเปลี่ยนแปลงประวัติเล็กน้อยบางอย่างถ้าจำเป็น

วิธีแก้ปัญหาค่อนข้างยุ่งเนื่องจากฉันต้องการสร้างฟังก์ชันทริกเกอร์โดยอัตโนมัติ ฉัน SQLAlchemy ดังนั้นฉันจึงสามารถสร้างตารางประวัติโดยทำ hijinks การสืบทอดซึ่งเป็นสิ่งที่ดี แต่ฟังก์ชันทริกเกอร์ที่เกิดขึ้นจริงต้องใช้สตริงที่ munging เพื่อสร้างฟังก์ชัน PostgreSQL อย่างถูกต้องและแมปคอลัมน์จากตารางหนึ่งไปยัง อีกอย่างถูกต้อง

ยังไงก็ตามก็ทั้งหมดบน GitHub ที่นี่

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