Wo sollten Sie Fremdschlüssel definieren?

Antworten:

41

Stellen Sie die Fremdschlüssel in die Datenbank. Selbst wenn Sie die Daten in der Anwendung validieren, bevor Sie sie speichern, sind die FKs eine gute QS-Sicherung. Für eine erste Annäherung haben Anwendungen immer Datenprobleme. Wenn Sie solche Steuerelemente nicht im System verwenden, werden nur Fehlermodi aufgerufen, bei denen Daten unbemerkt beschädigt werden.

Es gibt nichts Schöneres als ein paar Jahre im Data Warehousing zu arbeiten, um dies in Aktion zu sehen. Sie verbringen Ihre Zeit damit, die Teile nach unauffälligen Fehlern von Anwendungsentwicklern zu sammeln, die dachten, sie könnten die Datenintegrität im Anwendungscode durchsetzen. Wenn Sie dies tun, werden Sie zu dem Schluss kommen, dass die Integrität anwendungsgesteuerter Daten kaum mehr als eine Täuschung ist.

Darüber hinaus kann der Abfrageoptimierer Fremdschlüssel verwenden, um Rückschlüsse auf Tabellenverknüpfungen zu ziehen, sodass FKs zu effizienteren Abfrageplänen führen.

Fremdschlüssel bieten noch viele weitere Vorteile. Tun Sie allen einen Gefallen - stellen Sie die FK's in die Datenbank.

Betroffen vonTunbridgeWells
quelle
15

Referentielle Integrität sollte auf der niedrigstmöglichen Ebene behandelt werden, bei der es sich um die zugrunde liegende Datenbank handelt. Relationale Datenbankverwaltungssysteme sind darauf optimiert. Es macht keinen Sinn, das sprichwörtliche Rad neu zu erfinden.

Es ist akzeptabel, Domänenlogik im Anwendungscode zu definieren, um zu verhindern, dass die DML-Anweisung sogar eine RI-Ausnahme verursacht. Dies sollte jedoch nicht als Ersatz für Fremdschlüsselbeziehungen in der Datenbank angesehen werden.

Thomas Stringer
quelle
12

Ich werde hier voll und ganz aufhorchen lassen, da es sich um eine DBA-fokussierte Gruppe handelt.

Ich stimme zu, dass die Verwendung strenger Fremdschlüssel in den meisten Szenarien die beste Entscheidung ist. Es gibt jedoch einige Fälle, in denen Fremdschlüssel mehr Probleme verursachen als lösen.

Wenn Sie mit einer sehr hochgradig parallelen Umgebung wie einer stark frequentierten Webanwendung arbeiten und einen gut etablierten, robusten ORM verwenden, können Fremdschlüssel Sperrprobleme verursachen, die die Skalierung und Wartung eines Servers erschweren. Beim Aktualisieren von Zeilen in einer untergeordneten Tabelle wird auch die übergeordnete Zeile gesperrt. In vielen Szenarien kann dies die Parallelität aufgrund von Sperrkonflikten drastisch einschränken. Außerdem müssen Sie manchmal einzelne Tabellen warten, z. B. Archivierungsprozesse, bei denen Sie möglicherweise (absichtlich) die Regeln für die referenzielle Integrität zumindest vorübergehend brechen müssen. Bei vorhandenen Fremdschlüsseln kann dies sehr schwierig sein, und bei einigen RDBMS führt das Deaktivieren von Fremdschlüsseleinschränkungen zu einer Neuerstellung der Tabelle. Dies ist ein zeitaufwändiger Prozess, der erhebliche Ausfallzeiten erfordern kann.

Verstehen Sie, dass ich die Einschränkung einbeziehe, dass Sie ein robustes Framework verwenden müssen, das die referenzielle Integrität außerhalb der Datenbank verstehen kann. Dennoch werden Sie wahrscheinlich einige Probleme mit der referenziellen Integrität haben. Es gibt jedoch viele Fälle, in denen verwaiste Zeilen oder geringfügige Verstöße gegen die referenzielle Integrität keine große Rolle spielen. Ich würde argumentieren, dass die Mehrheit der Webanwendungen in diese Kategorie fällt.

Davon abgesehen fängt niemand als Facebook an. Beginnen Sie mit der Definition von Fremdschlüsseln in Ihrer Datenbank. Monitor. Wenn Sie Probleme haben, müssen Sie möglicherweise einige dieser Einschränkungen aufheben, um skalieren zu können.

Fazit: Die meisten Datenbanken sollten Fremdschlüssel haben. Umgebungen mit hoher Gleichzeitigkeit sind ohne Fremdschlüssel möglicherweise besser geeignet. Wenn Sie diesen Punkt erreichen, müssen Sie möglicherweise in Betracht ziehen, diese Einschränkungen aufzuheben.

Ich ziehe jetzt meinen flammhemmenden Anzug an.

EDIT 2012-03-23 ​​7:00 AM

Bei meinen Überlegungen zu den Sperren von Fremdschlüsseln habe ich die Kosten aller zusätzlichen Zeilensuchen, die implizit intern generiert werden und die Serverlast erhöhen, vernachlässigt.

Letztendlich ist mein Punkt, dass Fremdschlüssel nicht frei sind. In vielen Fällen sind die Kosten es wert, aber es gibt Szenarien, in denen diese Kosten ihren Nutzen übersteigen.

EDIT 2012-03-23 ​​7:38 AM

Seien wir konkret. In diesem Beispiel wähle ich MySQL / InnoDB, das wegen seines Fremdschlüsselverhaltens nicht besonders geschätzt wird, aber mir am vertrautesten ist und wahrscheinlich die am häufigsten verwendete Webdatenbank ist. Ich bin mir nicht sicher, ob andere Datenbanken mit dem Beispiel, das ich zeigen werde, besser abschneiden würden.

Stellen Sie sich eine untergeordnete Tabelle mit einem Fremdschlüssel vor, der auf den übergeordneten Schlüssel verweist. Ein Beispiel finden Sie in den Tabellen film und film_actor in der Sakila-Beispieldatenbank in MySQL:

CREATE TABLE `film` (
  `film_id` smallint(5) unsigned NOT NULL AUTO_INCREMENT,
  `title` varchar(255) NOT NULL,
  `description` text,
  `release_year` year(4) DEFAULT NULL,
  `language_id` tinyint(3) unsigned NOT NULL,
  `original_language_id` tinyint(3) unsigned DEFAULT NULL,
  `rental_duration` tinyint(3) unsigned NOT NULL DEFAULT '3',
  `rental_rate` decimal(4,2) NOT NULL DEFAULT '4.99',
  `length` smallint(5) unsigned DEFAULT NULL,
  `replacement_cost` decimal(5,2) NOT NULL DEFAULT '19.99',
  `rating` enum('G','PG','PG-13','R','NC-17') DEFAULT 'G',
  `special_features` set('Trailers','Commentaries','Deleted Scenes','Behind the Scenes') DEFAULT NULL,
  `last_update` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
  PRIMARY KEY (`film_id`),
  KEY `idx_title` (`title`),
  KEY `idx_fk_language_id` (`language_id`),
  KEY `idx_fk_original_language_id` (`original_language_id`),
  CONSTRAINT `fk_film_language` FOREIGN KEY (`language_id`) REFERENCES `language` (`language_id`) ON UPDATE CASCADE,
  CONSTRAINT `fk_film_language_original` FOREIGN KEY (`original_language_id`) REFERENCES `language` (`language_id`) ON UPDATE CASCADE
) ENGINE=InnoDB AUTO_INCREMENT=1001 DEFAULT CHARSET=utf8

CREATE TABLE `film_actor` (
  `actor_id` smallint(5) unsigned NOT NULL,
  `film_id` smallint(5) unsigned NOT NULL,
  `last_update` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
  PRIMARY KEY (`actor_id`,`film_id`),
  KEY `idx_fk_film_id` (`film_id`),
  CONSTRAINT `fk_film_actor_actor` FOREIGN KEY (`actor_id`) REFERENCES `actor` (`actor_id`) ON UPDATE CASCADE,
  CONSTRAINT `fk_film_actor_film` FOREIGN KEY (`film_id`) REFERENCES `film` (`film_id`) ON UPDATE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8

Die relevante Einschränkung ist film_actor (fk_film_actor_film) für mein Beispiel.

session1> BEGIN;
session1> INSERT INTO film_actor (actor_id, film_id) VALUES (156, 508);
Query OK, 1 row affected (0.00 sec)

session2> BEGIN;
session2> UPDATE film SET release_year = 2005 WHERE film_id = 508;
ERROR 1205 (HY000): Lock wait timeout exceeded; try restarting transaction

Beachten Sie, dass ich beim Einfügen in die untergeordnete Tabelle ein nicht verknüpftes Feld in der übergeordneten Zeile nicht aktualisieren konnte. Dies liegt daran, dass InnoDB aufgrund der FK-Einschränkung für film_actor eine gemeinsame Sperre für die Zeile hält, in der film.film_id = 508, sodass das UPDATE für diese Zeile die erforderliche exklusive Sperre nicht erhalten kann. Wenn Sie diesen Vorgang rückgängig machen und zuerst das UPDATE ausführen, haben Sie das gleiche Verhalten, aber das INSERT ist blockiert.

session1> BEGIN;
session1> UPDATE film SET release_year = 2005 WHERE film_id = 508;
Query OK, 1 row affected (0.00 sec)

session2> BEGIN;
session2> INSERT INTO film_actor (actor_id, film_id) VALUES (156, 508);
ERROR 1205 (HY000): Lock wait timeout exceeded; try restarting transaction

Stellen Sie sich eine usersTabelle in einer Webanwendung vor, in der es häufig Dutzende verwandter Tabellen gibt. Grundsätzlich verhindert jede Operation in einer verwandten Zeile eine Aktualisierung der übergeordneten Zeile. Dies kann ein herausforderndes Problem sein, wenn Sie mehrere Fremdschlüsselbeziehungen und viel Parallelität haben.

FK-Einschränkungen können auch Workarounds für die Tabellenwartung schwierig machen. Peter Zaitsev von Percona hat einen Blogbeitrag darüber, der es besser erklärt als ich es kann: Innodb Foreign Keys entführen .

Aaron Brown
quelle
Kommentare sind nicht für längere Diskussionen gedacht. Diese Unterhaltung wurde in den Chat verschoben .
Paul White sagt GoFundMonica
6

Es wird empfohlen, Fremdschlüssel in der Datenbank zu verwenden. Es hilft-

  • um die Datenintegrität zu erhalten, indem die Möglichkeit unerwünschter Daten beseitigt wird
  • die Leistung steigern. In Systemen, in denen Felder automatisch indiziert werden, können Fremdschlüsselreferenzen zu einer Leistungssteigerung führen
  • weniger Code durch den Programmierer zu schreiben. wie mitON DELETE CASCADE
Abdul Ahad
quelle