Ich habe eine Frage zum Datenbankdesign. Ich frage hier, weil ich ein Enthusiast / Hobbyist und kein "Profi" bin, also möchte ich es nicht in den Stapelaustausch "Datenbankadministratoren" stellen, der speziell auf Profis ausgerichtet ist. Ich hoffe das ist der richtige Ort.
Ich möchte ein System aufbauen, um Begegnungen zwischen Gefangenen und Strafvollzugsbeamten zu verfolgen. Beim Entwerfen einer relationalen Datenbank habe ich die folgenden fünf Tabellen gefunden:
CREATE TABLE `encounters` (
`id` INT NOT NULL,
`encounterdate` DATETIME NULL,
`officers_id` INT NOT NULL,
`prisoners_id` INT NOT NULL,
PRIMARY KEY (`id`)
);
CREATE TABLE `officers` (
`id` INT NOT NULL,
`badgenumber` VARCHAR(10) NULL,
`lastnames_id` INT NOT NULL,
`firstnames_id` INT NOT NULL,
PRIMARY KEY (`id`)
);
CREATE TABLE `prisoners` (
`id` INT NOT NULL,
`regnumber` VARCHAR(10) NULL,
`lastnames_id` INT NOT NULL,
`firstnames_id` INT NOT NULL,
PRIMARY KEY (`id`)
);
CREATE TABLE `firstnames` (
`id` INT NOT NULL,
`name` VARCHAR(45) NULL,
PRIMARY KEY (`id`)
);
CREATE TABLE `lastnames` (
`id` INT NOT NULL,
`name` VARCHAR(45) NULL,
PRIMARY KEY (`id`)
);
mit folgenden Beziehungen:
Dieses Setup würde mich daran hindern, alle Vor- und Nachnamen zweimal zu speichern (einmal für die Beamten und einmal für die Gefangenen), aber ich bin nicht sicher, wie ich den Vor- / Nachnamen eines bestimmten Beamten UND den Vor- / Nachnamen eines bestimmten Gefangenen abrufen soll für eine gegebene Begegnung. Im Idealfall möchte ich eine SELECT-Anweisung verwenden, um einen Datensatz zu erhalten, der wie eine der folgenden Zeilen aussieht:
Ich kann innere Verknüpfungen verwenden, um Vor- und Nachnamen für einen Offizier zu erhalten:
SELECT
encounters.encounterdate,
officers.badgenumber,
prisoners.regnumber,
fnames.name,
lnames.name
FROM
encounters
INNER JOIN prisoners ON encounters.prisoners_id = prisoners.id
INNER JOIN officers ON encounters.officers_id = officers.id
INNER JOIN fnames on officers.firstnames_id = fnames.id
INNER JOIN lnames on officers.lastnames_id = lnames.id
WHERE
officers.badgenumber = "b503"
oder ein Gefangener:
SELECT
encounters.encounterdate,
officers.badgenumber,
prisoners.regnumber,
fnames.name,
lnames.name
FROM
encounters
INNER JOIN prisoners ON encounters.prisoners_id = prisoners.id
INNER JOIN officers ON encounters.officers_id = officers.id
INNER JOIN fnames on prisoners.firstnames_id = fnames.id
INNER JOIN lnames on prisoners.lastnames_id = lnames.id
WHERE
officers.badgenumber = "b503"
aber ich kann nicht herausfinden, ob es möglich ist, BEIDE für eine gegebene Begegnung mit nur einer SELECT-Anweisung zu erhalten.
Natürlich könnte ich es mit einer gespeicherten Prozedur / Funktion und ein paar SELECTs machen, aber ich bin interessiert zu hören, ob es einen einfacheren Weg gibt, es mit einem SELECT zu machen. Oder ist dies nur ein schlechter Weg, um eine Datenbank zu entwerfen?
Danke für Ihre Hilfe.
Antworten:
Ihr Beispiel mit Vor- und Nachnamen ist interessant. Was fügt es dem Bild hinzu? Welchen Wert hat es, Vornamen in eine separate Tabelle zu setzen? Wenn Sie alle Personen mit dem Vornamen "Marc" nehmen, was haben Sie dann? Bedeutet es etwas? Was ist, wenn Sie alle Personen mit dem Nachnamen "Smith" nehmen - gehören sie alle zu einer Familie, einem Clan, einer Rasse oder einer Nationalität? Leben sie alle in derselben Stadt? Wahrscheinlich nicht!
Wenn der Name "Smith" bedeutet, dass Sie braune Haare und blaue Augen haben und sich normalerweise im Cowboy-Stil kleiden, ist dies sinnvoll. Eine mögliche Analogie ist hier: Wenn es sich bei dem Artikel um ein Produkt des Typs TV handelt, verfügt er wahrscheinlich über eine Fernbedienung, benötigt ein Stromkabel usw.
Wenn Namen wie 1 MB groß wären, wäre es sinnvoll, eine ID zu verwenden. Das würde viel doppelten Speicherplatz sparen. Aber bei normalen Namen macht es keinen großen Unterschied, während es zu mehr Komplexität führt. Die Datenbank ist nicht nur komplexer, sondern auch der Code, mit dem die Verbindung zur Datenbank hergestellt wird, ist komplexer. Da es keinen Vorteil gibt, sollten Sie ihn besser vermeiden.
Da mit dem Vor- oder Nachnamen nichts Sinnvolles oder Nützliches verbunden ist, schreiben Sie ihn nicht in eine separate Tabelle.
Sie erwähnen in einem Kommentar, dass 240 KB eingespart werden könnten, wenn 20.000 Personen denselben Namen tragen. Das ist die meiste Zeit keine große Ersparnis. Natürlich gibt es Situationen, in denen dies sinnvoll ist, aber in der modernen Welt mit viel Speicherplatz ist die Einsparung von 1 MB Daten völlig irrelevant.
Wenn Sie das Speichern von Daten erwähnen, frage ich mich, ob es die Leistung beeinträchtigt oder nicht. Ich habe keine Ahnung, aber wenn wir über Zahlen sprechen und dies Facebook ist und wir täglich Millionen von Namen abfragen, frage ich mich, was effizienter sein wird, da dies eine zusätzliche Verknüpfung bedeutet. Dies sollte getestet werden und basierend auf diesem Test entscheiden Sie.
Wenn Sie extrem viele Anfragen haben oder nur sehr wenig Platz zur Verfügung haben und feststellen, dass die Verwendung eines zusätzlichen Tisches den Tag spart - tun Sie es!
quelle
Als Antwort auf Ihre Ja- oder Nein-Frage, ja. Einige Strukturen sind in angemessenem Maße besser denormalisiert. Was ist angemessen? Das hängt natürlich davon ab.
In Ihrem speziellen Beispiel ist die von AEonEX vorgeschlagene Antwort nicht wegen Denormalisierung richtig, sondern weil diese Namen die richtigen Attribute der Entitäten sind, die sie benennen. Es kann angebracht sein, einen Zustand aus einer Adresse heraus zu exportieren, da der Zustand real ist, existiert und sich alle Verweise darauf tatsächlich auf dieselbe reale Sache beziehen. Ein Name, nicht so sehr.
quelle
Es werden keine Tabellen
firstnames
und benötigtlastnames
. Speichern Sie stattdessen dasfirstname
undlastname
inofficers
undprisoners
anstelle vonfirstnames_id
undlastnames_id
.quelle