การออกแบบฐานข้อมูลสำหรับการบันทึกการตรวจสอบ


151

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

มีบางคำถามที่ถูกถามถึงที่นี่เกี่ยวกับเรื่องนี้ แต่ฉันไม่เห็นด้วยว่ามีวิธีการที่ดีที่สุดสำหรับทุกสถานการณ์:

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

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

  • ครบกําหนดของสคีมาฐานข้อมูล
  • วิธีสอบถามข้อมูลจะถูกสอบถาม
  • ความน่าจะเป็นที่จะต้องสร้างเร็กคอร์ดใหม่
  • มีความสำคัญมากกว่า: เขียนหรืออ่านประสิทธิภาพ
  • ลักษณะของค่าที่บันทึกไว้ (สตริง, ตัวเลข, blobs)
  • มีพื้นที่เก็บของว่าง

แนวทางที่ฉันรู้คือ:

1. เพิ่มคอลัมน์สำหรับวันที่สร้างและแก้ไขและผู้ใช้

ตัวอย่างตาราง:

  • รหัส
  • value_1
  • value_2
  • VALUE_3
  • วันที่สร้าง
  • MODIFIED_DATE
  • สร้างโดย
  • modified_by

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

2. ใส่เฉพาะตาราง

ตัวอย่างตาราง :

  • รหัส
  • value_1
  • value_2
  • VALUE_3
  • จาก
  • ถึง
  • ลบแล้ว (บูลีน)
  • ผู้ใช้งาน

ข้อเสียที่สำคัญ: จะทำให้คีย์ต่างประเทศทันสมัยอย่างไร? ต้องการพื้นที่ขนาดใหญ่

3. สร้างตารางประวัติแยกสำหรับแต่ละตาราง

ตัวอย่างตารางประวัติ:

  • รหัส
  • value_1
  • value_2
  • VALUE_3
  • VALUE_4
  • ผู้ใช้งาน
  • ลบแล้ว (บูลีน)
  • การประทับเวลา

ข้อเสียที่สำคัญ: ต้องทำซ้ำตารางที่ตรวจสอบทั้งหมด หากสคีมีการเปลี่ยนแปลงมันจะต้องโยกย้ายบันทึกทั้งหมดด้วย

4. สร้างตารางประวัติรวมสำหรับตารางทั้งหมด

ตัวอย่างตารางประวัติ:

  • table_name
  • สนาม
  • ผู้ใช้งาน
  • new_value
  • ลบแล้ว (บูลีน)
  • การประทับเวลา

ข้อเสียที่สำคัญ: ฉันจะสามารถสร้างบันทึก (ย้อนกลับ) ถ้าจำเป็นได้อย่างง่ายดาย? คอลัมน์ new_value จำเป็นต้องเป็นสตริงขนาดใหญ่เพื่อให้สามารถรองรับคอลัมน์ประเภทต่าง ๆ ได้ทั้งหมด


เกี่ยวข้อง: stackoverflow.com/questions/9852703/…
Kaii

1
และสิ่งที่เกี่ยวกับการใช้ฐานข้อมูลประวัติแทนตาราง?
Jowen

บางทีคุณสามารถตรวจสอบการออกแบบของgithub.com/airblade/paper_trail
zx1986

เป็นความคิดที่ดีหรือไม่ที่จะบันทึกการสืบค้นทั้งหมด (จำเป็น) ดำเนินการตามที่เป็นอยู่?
Dinushan

คำตอบ:


87

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

ตัวอย่างเช่นหากคุณมีตารางชื่อโอกาสในการติดตามข้อเสนอการขายคุณจะสร้างตารางแยกกันสองตาราง:

โอกาสโอกาส
_ เนื้อหา (หรืออะไรทำนองนั้น)

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

นี่คือตัวอย่างง่ายๆ:

CREATE TABLE dbo.Page(  
    ID int PRIMARY KEY,  
    Name nvarchar(200) NOT NULL,  
    CreatedByName nvarchar(100) NOT NULL, 
    CurrentRevision int NOT NULL, 
    CreatedDateTime datetime NOT NULL

และเนื้อหา:

CREATE TABLE dbo.PageContent(
    PageID int NOT NULL,
    Revision int NOT NULL,
    Title nvarchar(200) NOT NULL,
    User nvarchar(100) NOT NULL,
    LastModified datetime NOT NULL,
    Comment nvarchar(300) NULL,
    Content nvarchar(max) NOT NULL,
    Description nvarchar(200) NULL

ฉันอาจจะทำให้ PK ของตารางเนื้อหาเป็นคีย์หลายคอลัมน์จาก PageID และการแก้ไขให้การแก้ไขเป็นประเภทข้อมูลประจำตัว คุณจะใช้คอลัมน์ Revision เป็น FK จากนั้นคุณดึงระเบียนรวมโดยเข้าร่วมเช่นนี้

SELECT * FROM Page
JOIN PageContent ON CurrentRevision = Revision AND ID = PageID

อาจมีข้อผิดพลาดเกิดขึ้นที่นี่ ... มันอยู่ด้านบนของหัวฉัน ควรให้แนวคิดของรูปแบบทางเลือกแทน


10
ในแง่ของวิธีการตรวจสอบที่ดี แต่สำหรับการผลิตจะใช้เวลานานในการพัฒนาตารางตรวจสอบแยกต่างหากสำหรับแต่ละตารางในฐานข้อมูลการเขียนทริกเกอร์สำหรับแต่ละตารางเพื่อจับการเปลี่ยนแปลงและเขียนลงในตารางการตรวจสอบ นอกจากนี้ความท้าทายอย่างมากในการพัฒนารายงานการตรวจสอบบัญชีเดียวสำหรับทุกตารางเนื่องจากแต่ละตารางการตรวจสอบมีโครงสร้างที่แตกต่างกัน
asim-ishaq

11
หากการเขียนและการบำรุงรักษาสคริปต์สำหรับแต่ละตารางเป็นข้อกังวลสำหรับองค์กรที่ต้องการจัดการฐานข้อมูลที่ตรวจสอบแล้วฉันขอแนะนำให้จ้าง DBA ที่มีประสบการณ์หรือวิศวกรซอฟต์แวร์ที่มีความยืดหยุ่นสูงและมีประสบการณ์สูงและมีประสบการณ์เพียงพอในการสร้างฐานข้อมูลที่ตรวจสอบ .
Hardryv

1
ถูกต้องหรือไม่ว่าPageContent.PageIDเป็น FK ถึงPage.IDและPage.CurrentRevisionFK ถึงPageContent.Revisionหรือไม่ การพึ่งพานี้เป็นแบบวงกลมจริงๆหรือไม่?

2
ฉันลงคะแนนเนื่องจากไม่ได้กล่าวถึงตัวเลือกที่กล่าวถึง มันให้ตัวเลือกอื่นซึ่งเป็นทางออกที่เฉพาะเจาะจงกับกรณีการใช้งานที่เฉพาะเจาะจงมาก แต่ฉันเห็นข้อดีของการออกแบบที่แนะนำ
acteon

1
ฉันสามารถนึกถึงเขตข้อมูลน้อยมากที่ฉันสามารถพูดด้วยความมั่นใจจะไม่เปลี่ยนแปลงดังนั้นตาราง "หลัก" ทั้งหมดสำหรับแต่ละเอนทิตีจะจบลงด้วยการเป็นเพียงid, revision_id; ตารางแยกมากขึ้นจริงๆ มันทำให้ฉันรู้สึกเหม็น สิ่งนี้มีประโยชน์อย่างไรเมื่อเทียบกับวิธีที่ 3 ใน OP (ตารางประวัติต่อตารางที่ตรวจสอบแล้ว)
Kenmore

14

หากคุณใช้ SQL Server 2008 คุณอาจต้องพิจารณาเปลี่ยนการบันทึกข้อมูล นี่เป็นของใหม่สำหรับปี 2551 และสามารถช่วยคุณประหยัดงานได้มาก


นี่คือลิงค์ไปยังข้อมูลการติดตามการเปลี่ยนแปลงของ SQL 2012 msdn.microsoft.com/en-us/library/bb933994.aspx +1 สำหรับการใช้งานในตัวไม่มีจุดประดิษฐ์ล้อ
คริส

4
@Chris คุณเคยใช้มันด้วยตัวเอง? แน่นอนมันติดตามทุกอย่าง ... แต่ความสามารถในการรับข้อมูลที่เป็นประโยชน์ออกมาจากมันเป็นเรื่องราวอื่น ไม่สามารถใช้ล้อแทรคเตอร์สำหรับจักรยานของฉันได้
Jowen

นี้จริงๆจะได้รับน่ากลัว แต่ถ้าคุณมีSQL Server รุ่นมาตรฐานเช่นเดียวกับฉันคุณไม่มีโชค: "การดักจับข้อมูลการเปลี่ยนแปลงมีให้เฉพาะในรุ่นEnterprise , DeveloperและEnterprise Evaluation "
แบรด Turek

6

ฉันไม่รู้การอ้างอิง แต่ฉันแน่ใจว่ามีคนเขียนอะไรบางอย่าง

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

timestamp
username
ip_address
procedureName (if called from a stored procedure)
database
table
field
accesstype (insert, delete, modify)
oldvalue
newvalue

สมมุติว่าสิ่งนี้ถูกรักษาโดยทริกเกอร์


ฉันไม่รู้วิธีการรับสิ่งนั้นภายในเซิร์ฟเวอร์ฐานข้อมูล แต่แน่นอนว่าสามารถทำได้จากภายนอกก็เพียงพอแล้ว
wallyk

5
ฉันคิดว่านี่เป็นรูปแบบการออกแบบเดียวกับตัวเลือกที่ 4 ที่แสดงในคำถามเดิม
givanse

3

เราจะสร้างฐานข้อมูลตัวอย่างเล็ก ๆ สำหรับแอปพลิเคชันบล็อก ต้องมีสองตาราง:

blog: เก็บรหัสโพสต์ที่ไม่ซ้ำกันชื่อเนื้อหาและการตั้งค่าสถานะที่ถูกลบ audit: เก็บชุดการเปลี่ยนแปลงพื้นฐานที่ผ่านมาพร้อมกับรหัสการบันทึกรหัสการโพสต์บล็อกประเภทการเปลี่ยนแปลง (ใหม่แก้ไขหรือลบ) และวันที่ / เวลาของการเปลี่ยนแปลงนั้น SQL ต่อไปนี้สร้างblogและสร้างดัชนีคอลัมน์ที่ถูกลบ:

CREATE TABLE `blog` (
    `id` mediumint(8) unsigned NOT NULL AUTO_INCREMENT,
    `title` text,
    `content` text,
    `deleted` tinyint(1) unsigned NOT NULL DEFAULT '0',
    PRIMARY KEY (`id`),
    KEY `ix_deleted` (`deleted`)
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8 COMMENT='Blog posts';

SQL ต่อไปนี้สร้างauditตาราง คอลัมน์ทั้งหมดมีการทำดัชนีและมีการกำหนดคีย์ต่างประเทศสำหรับ audit.blog_id ซึ่งอ้างอิง blog.id ดังนั้นเมื่อเราลบรายการบล็อกทางกายภาพประวัติการตรวจสอบทั้งหมดจะถูกลบด้วย

CREATE TABLE `audit` (
    `id` mediumint(8) unsigned NOT NULL AUTO_INCREMENT,
    `blog_id` mediumint(8) unsigned NOT NULL,
    `changetype` enum('NEW','EDIT','DELETE') NOT NULL,
    `changetime` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
    PRIMARY KEY (`id`),
    KEY `ix_blog_id` (`blog_id`),
    KEY `ix_changetype` (`changetype`),
    KEY `ix_changetime` (`changetime`),
    CONSTRAINT `FK_audit_blog_id` FOREIGN KEY (`blog_id`) REFERENCES `blog` (`id`) ON DELETE CASCADE ON UPDATE CASCADE
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8;

2

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

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

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

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