Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Maintaining Referential Integrity - Good or Bad?

We are planning on introducing simple Audit Trail in our database using triggers and separate history table for each table that requires auditing.

For example consider table StudentScore, it has few foreign keys (eg. StudentID, CourseID) linking it to corresponding parent tables (Student & Course).

Table StudentScore (     StudentScoreID, -- PK     StudentID ref Student(StudentID),  -- FK to Student     CourseID ref Course(CourseID),   -- FK to Course ) 

If StudentScore requires auditing, we are planning to create audit table StudentScoreHistory -

Table StudentScoreHistory (     StudentScoreHistoryID, -- PK     StudentScoreID,     StudentID,     CourseID,     AuditActionCode,     AuditDateTime,     AuditActionUserID ) 

If any row in StudentScore is modified we'll move old row to StudentScoreHistory.

One of the points raised during design discussion was to make StudentID and CourseID in StudentHistory table a FK, to maintain referential integrity. Argument made in favour of this was as we always mostly do a soft (logical Boolean flag) delete rather than hard delete, its good to maintain referential integrity to ensure we do not have any orphan ids in audit table.

Table StudentScoreHistory (     StudentScoreHistoryID, -- PK     StudentScoreID,     StudentID ref Student(StudentID), -- FK to Student     CourseID ref Course(CourseID), -- FK to Course     AuditActionCode,     AuditDateTime,     AuditActionUserID ) 

This seems to be a bit odd design to me. I do agree with @Jonathan Leffler's comment that audit record should not stop the deletion of parent data. Instead, if this is required, should be handled via foreign keys in main table and not in audit table. I want to get your opinion, to make sure I'm not missing some value in extending foreign keys to audit tables.

Now my question is: Is it a good design to have these foreign keys in History tables?

Any details on key arguments (e.x. performance, best practice, design flexibility etc) would be highly appreciated.

For benefit of anyone looking for specific purpose and our environment:

Purpose:

  1. Maintain critical data history
  2. Allow auditing of user activity with support to recreate scenario
  3. To limited extent allow roll-back of user activity

Environment:

  • Transactional database
  • Not every table requires auditing
  • Uses soft-delete to the extent possible, specifically for static/reference data
  • Few highly transactional tables do use hard deletes
like image 617
YetAnotherUser Avatar asked Apr 26 '11 17:04

YetAnotherUser


People also ask

Why is it important to maintain referential integrity?

Referential integrity ensures that the relationship between two tables keeps in sync during the execution of the update and delete instructions.

Should you always enforce referential integrity?

When you create a relationship between two tables, it is usually a good idea to enforce referential integrity. Referential integrity keeps data accurate and ensures that you don't accidentally change or delete related data in one table but not in the other.

What happens if there is no referential integrity?

In simple terms, 'referential integrity' guarantees that the target 'referred' to will be found. A lack of referential integrity in a database can lead relational databases to return incomplete data, usually with no indication of an error.

What can happen if referential integrity is not maintained in a relational database management system?

By default, the database server does not allow you to violate referential integrity and gives you an error message if you attempt to delete rows from the parent table before you delete rows from the child table.


1 Answers

When discussing auditing, I would go back to the purpose behind it. It isn't really a backup but rather a history of what has been. For example, for StudentScore, you would want to be sure not to lose the fact that the student originally had a 65% when they now have a 95%. This audit trail would allow you to walk back through the changes to see what happened and who did it. From this, you could identify what a particular user did to abuse the system. In some ways this could be a type of backup since you could roll back these changes to their previous states without rolling back entire tables.

With this in mind (if my assumptions about what you are using this for are correct), the only place you would want a FK/PK relationship is between the history table and its "live" counterpart. Your audit (history) table should not refer to any other table because it is no longer a part of that system. Instead, it is simply a record of what has happened in one table. Period. The only referential integrity you might want to consider is between the history table and the live table (thus the possible FK/PK relationship). If you allow records to be deleted from the live table, don't include the FK in the history table. Then the history table could include deleted records (which is what you want if you allow deletions).

Don't get confused with relational integrity in the main database with this history table. The history tables are all stand-alone. They only serve as a history of one table (not a set of tables).

The relating of two history tables together is possible and even more advanced relations between the live and history tables together (Students and Courses with both live and history, for example) so you can deal with even the possibility that a student was deleted (shudder) since the record would still be in the history table. The only issue here would be if you don't keep the history for a particular table, in which case you are choosing to lose that data (if you allow deletes).

like image 65
IAmTimCorey Avatar answered Oct 04 '22 05:10

IAmTimCorey