it-swarm.com.de

Ist es verschwenderisch, eine neue Datenbanktabelle zu erstellen, anstatt den Datentyp enum zu verwenden?

Angenommen, ich biete vier Arten von Diensten an (es ist unwahrscheinlich, dass sie sich häufig ändern):

  • Testen
  • Design
  • Programmierung
  • Andere

Angenommen, ich habe 60-80 tatsächliche Dienste, die jeweils in eine der oben genannten Kategorien fallen. Beispielsweise kann "ein Dienst" "Testprogramm mit Technik A" sein und ist vom Typ "Testen".

Ich möchte sie in eine Datenbank kodieren. Ich habe mir ein paar Optionen ausgedacht:

Option 0:

Verwenden Sie VARCHAR direkt, um den Diensttyp direkt als Zeichenfolge zu codieren

Option 1:

Verwenden Sie die Datenbank enum. Aber Aufzählung ist böse

Option 2:

verwenden Sie zwei Tabellen:

service_line_item (id, service_type_id INT, description VARCHAR);
service_type (id, service_type VARCHAR);

Ich kann sogar referenzielle Integrität genießen:

ALTER service_line_item 
    ADD FOREIGN KEY (service_type_id) REFERENCES service_type (id);

Hört sich gut an, ja?

Aber ich muss immer noch Dinge codieren und mit ganzen Zahlen umgehen, d. H. Beim Auffüllen der Tabelle. Oder ich muss aufwendige Programmier- oder DB-Konstrukte erstellen, wenn ich die Tabelle auffülle oder damit arbeite. JOINs, wenn Sie sich direkt mit der Datenbank befassen oder neue objektorientierte Entitäten auf der Programmierseite erstellen und sicherstellen, dass ich sie korrekt betreibe.

Option 3:

Verwenden Sie nicht enum, sondern keine zwei Tabellen, sondern nur eine Ganzzahlspalte

service_line_item (
    id,
    service_type INT,        -- use 0, 1, 2, 3 (for service types)
    description VARCHAR
);

Dies ist wie eine 'falsche Aufzählung', die mehr Overhead auf der Codeseite der Dinge erfordert, wie d. H. Zu wissen, dass {2 == 'Programming'} und angemessen damit umgehen.

Frage:

Derzeit habe ich es mit Option 2 implementiert, die unter Konzepten geführt wird

  1. verwenden Sie keine Aufzählung (Option 1)
  2. vermeiden Sie die Verwendung einer Datenbank als Tabellenkalkulation (Option 0).

Aber ich kann nicht anders, als das Gefühl zu haben, dass mir das in Bezug auf Programmierung und kognitiven Aufwand verschwenderisch erscheint - ich muss zwei Tabellen kennen und mich mit zwei Tabellen gegen eine befassen.

Für einen 'weniger verschwenderischen Weg' schaue ich auf Option 3. Die IT ist leichter und erfordert im Wesentlichen dieselben Codekonstrukte (mit geringfügigen Änderungen, aber Komplexität und Struktur sind im Wesentlichen gleich, jedoch mit einer einzigen Tabelle).

Ich nehme an, im Idealfall ist es nicht immer verschwenderisch, und es gibt gute Fälle für beide Optionen, aber gibt es eine gute Richtlinie, wann man Option 2 verwenden sollte und wann Option 3?

Wenn es nur zwei Typen gibt (binär)

Um dieser Frage ein bisschen mehr hinzuzufügen ... am selben Ort habe ich eine binäre Option für "Standard" - oder "Ausnahme" -Dienst, die für die Service-Werbebuchung gelten kann. Ich habe das mit Option 3 codiert.

Ich habe beschlossen, keine neue Tabelle zu erstellen, nur um die Werte {"Standard", "Ausnahme"} zu speichern. Meine Spalte enthält also nur {0, 1} und mein Spaltenname heißt exception, und mein Code führt eine Übersetzung von {0, 1} => {STANDARD, EXCEPTION} (die ich als Konstanten in der Programmiersprache codiert habe)

Bisher gefällt mir das auch nicht ..... (Option 2 oder Option 3 gefällt mir nicht). Ich finde Option 2 besser als 3, aber mit mehr Overhead, und trotzdem kann ich mich der Codierung von Dingen als Ganzzahlen nicht entziehen, unabhängig davon, welche Option ich von 2 und 3 verwende.

[~ # ~] orm [~ # ~]

Um nach dem Lesen der Antworten einen Kontext hinzuzufügen, habe ich gerade (vor kurzem) wieder mit der Verwendung eines ORM begonnen, in meinem Fall Doctrine 2. Nach dem Definieren des DB-Schemas über Anmerkungen wollte ich die Datenbank füllen. Da mein gesamter Datensatz relativ klein ist, wollte ich versuchen, Programmierkonstrukte zu verwenden, um zu sehen, wie es funktioniert.

Ich habe zuerst service_types und dann service_line_items, da eine Liste aus einer tatsächlichen Tabelle vorhanden war. Dinge wie 'Standard/Ausnahme' und 'Testen' sind also alle Zeichenfolgen in der Tabelle und müssen in die richtigen Typen codiert werden, bevor sie in der Datenbank gespeichert werden.

Ich fand dies SO Antwort: Was verwenden Sie anstelle von ENUM in Doctrine2? , was vorschlug, nicht das Enum-Konstrukt von DB zu verwenden, sondern ein INT Feld und zum Codieren der Typen mit dem Konstrukt 'const' der Programmiersprache.

Aber wie in der obigen Frage erwähnt SO Frage, kann ich die direkte Verwendung von ganzen Zahlen vermeiden und Sprachkonstrukte - Konstanten - verwenden, sobald sie definiert sind ....

Aber trotzdem ... egal wie Sie es drehen, wenn ich mit string als Typ beginne, muss ich es zuerst in einen richtigen Typ konvertieren, selbst wenn ich ein ORM verwende.

Also wenn sagen $str = 'Testing';, Ich brauche noch irgendwo einen Block, der so etwas macht wie:

switch($str):
{ 
    case 'Testing':  $type = MyEntity::TESTING; break;
    case 'Other':    $type = MyEntity::OTHER; break;
}

Das Gute ist, dass Sie sich nicht mit ganzen Zahlen/magischen Zahlen beschäftigen [stattdessen mit codierten konstanten Mengen], aber das Schlechte ist, dass Sie ohne diesen Konvertierungsschritt keine Dinge automatisch in die Datenbank hinein- und herausziehen können Wissen.

Und das habe ich teilweise damit gemeint, dass ich Dinge wie "muss noch Dinge codieren und mit ganzen Zahlen umgehen" sagte. (Zugegeben, jetzt, nach Ocramius 'Kommentar, muss ich mich nicht direkt mit ganzen Zahlen befassen, sondern mit benannten Konstanten und einigen Konvertierungen in/von Konstanten, falls erforderlich).

43
Dennis

Option 2 unter Verwendung von Referenztabellen ist die Standardmethode. Es wurde von Millionen von Programmierern verwendet und funktioniert bekanntermaßen. Es ist ein Muster, so dass jeder andere, der sich Ihre Sachen ansieht, sofort weiß, was los ist. Es gibt Bibliotheken und Tools, die mit Datenbanken arbeiten und Ihnen viel Arbeit ersparen, damit Sie richtig damit umgehen können. Die Vorteile der Verwendung sind unzählig.

Ist es verschwenderisch? Ja, aber nur geringfügig. In jeder halbwegs anständigen Datenbank werden solche häufig verknüpften kleinen Tabellen immer zwischengespeichert, sodass die Verschwendung im Allgemeinen nicht wahrnehmbar ist.

Alle anderen von Ihnen beschriebenen Optionen sind ad hoc und hackig, einschließlich MySQLs enum, da es nicht Teil des SQL-Standards ist. (Abgesehen davon ist das, was an enum scheiße ist, die Implementierung von MySQL, nicht die Idee selbst. Es würde mir nichts ausmachen, sie eines Tages als Teil des Standards zu sehen.)

Ihre letzte Option Nr. 3 bei der Verwendung einer einfachen Ganzzahl ist besonders hacky. Sie erhalten die schlimmste aller Welten: keine referenzielle Integrität, keine benannten Werte, kein endgültiges Wissen in der Datenbank darüber, wofür ein Wert steht, nur willkürliche Ganzzahlen, die überall herumgeworfen werden. Mit diesem Token können Sie auch die Verwendung von Konstanten in Ihrem Code beenden und stattdessen fest codierte Werte verwenden. circumference = radius * 6.28318530718;. Wie ist es damit?

Ich denke, Sie sollten noch einmal prüfen, warum Sie Referenztabellen als lästig empfinden. Soweit ich weiß, findet sie niemand anders belastend. Könnte es sein, dass Sie nicht die richtigen Werkzeuge für den Job verwenden?

Ihr Satz über das "Codieren von Dingen und den Umgang mit ganzen Zahlen" oder das Erstellen von "aufwändigen Programmierkonstrukten" oder "das Erstellen neuer objektorientierter Entitäten auf der Programmierseite" sagt mir, dass Sie möglicherweise versuchen, objektrelational zu arbeiten Mapping (ORM) im laufenden Betrieb im gesamten Code Ihrer Anwendung verteilt, oder im besten Fall versuchen Sie, Ihren eigenen objektrelationalen Mapping-Mechanismus zu implementieren, anstatt ein vorhandenes ORM-Tool für den Job zu verwenden, z. B. Hibernate. All diese Dinge sind mit Hibernate ein Kinderspiel. Es dauert eine Weile, bis Sie es gelernt haben, aber wenn Sie es erst einmal gelernt haben, können Sie sich wirklich auf die Entwicklung Ihrer Anwendung konzentrieren und die grundlegenden Mechanismen für die Darstellung von Inhalten in der Datenbank vergessen.

Wenn Sie sich das Leben bei der direkten Arbeit mit der Datenbank erleichtern möchten, können Sie mindestens zwei Dinge tun, an die ich jetzt denken kann:

  1. Erstellen Sie Ansichten, die Ihre Haupttabellen mit den Referenztabellen verknüpfen, auf die sie verweisen, sodass jede Zeile nicht nur die Referenz-IDs, sondern auch die entsprechenden Namen enthält.

  2. Verwenden Sie anstelle einer Ganzzahl-ID für die Referenztabelle eine CHAR (4) -Spalte mit 4-Buchstaben-Abkürzungen. Die IDs Ihrer Kategorien würden also zu "TEST", "DSGN", "PROG", "OTHR". (Ihre Beschreibungen würden natürlich richtige englische Wörter bleiben.) Es wird etwas langsamer sein, aber vertrau mir, niemand wird es bemerken.

Wenn es nur zwei Typen gibt, verwenden die meisten Leute nur eine boolesche Spalte. Diese "Standard/Ausnahme" -Spalte würde also als Boolescher Wert implementiert und als "IsException" bezeichnet.

40
Mike Nakis

Option 2 mit Konstanten oder Aufzählungen am Programmierende.
Obwohl es Wissen dupliziert und gegen das Prinzip der Single Source Of Truth verstößt, können Sie es mit der Fail-Fast -Technik behandeln. Wenn Ihr System geladen wird, wird überprüft, ob die Aufzählungen oder konstanten Werte in der Datenbank vorhanden sind. Wenn nicht, sollte das System einen Fehler auslösen und das Laden verweigern. Es ist im Allgemeinen billiger, diesen Fehler zu diesem Zeitpunkt zu beheben, als später, wenn möglicherweise etwas Schwerwiegenderes passiert ist.

option 2 ist die ideale Wahl. Der Overhead ist nicht so hoch, dass andere Optionen in Betracht gezogen werden müssen. Mit dieser Option bleibt die Datenbank organisiert und leicht verständlich.

Option 3 ist schneller als Option 2, aber Sie müssen nachverfolgen, welche Ganzzahl was bedeutet. Wenn Sie aus irgendeinem Grund die Nummer ändern möchten, sind möglicherweise an vielen Stellen in Ihrem Code einige Änderungen erforderlich. Als Programmierer sollte sichergestellt sein, dass es keine Lücken in der Architektur gibt und dass es einen Spitzenplatz gibt, von dem aus ich eine bestimmte Aufgabe steuern kann.

0
Ravish

Nichts hindert Sie daran, [kurze] Zeichenfolgen als Schlüssel zu verwenden, sodass Sie die Lesbarkeit von Namen in Ihren Tabellen weiterhin haben und nicht auf eine bedeutungslose Ersatznummerncodierung zurückgreifen können. Sie sollten immer noch eine separate Tabelle zur Beschreibung der Servicetypen haben, nur für den Fall, dass Ihre Bewerbung beispielsweise international wird!

Ihre Benutzer können Ihre vier Kategorien in ihrer eigenen Sprache sehen, aber Ihre Datenbanktabellen enthalten immer noch Werte, die Sie lesen können - und keine davon erfordert Datenbankstruktur- oder Codeänderungen!

table service_type 
( id VARCHAR 
, name VARCHAR 
  primary key ( id ) 
);
table service_line_item 
( id 
, service_type VARCHAR 
, description VARCHAR
  foreign key ( service_type ) references service_type ( id )
);

select * from service_type ; 

+-------------+----------------+
| id          | name           |
+-------------+----------------+
| Testing     | Testen         |
| Design      | Design         | 
| Programming | Programmierung |
| Other       | Andere         |
+-------------+----------------+

oder für Ihre französischen Kunden ...

update services_types set name = 'Essai'         where id = 'Testing'; 
update services_types set name = 'Conception'    where id = 'Design'; 
update services_types set name = 'Programmation' where id = 'Programming'; 
update services_types set name = 'Autre'         where id = 'Other'; 
0
Phill W.