Mögliche Vorteile des Speicherns mehrerer Werte in einem Feld einer Zeile anstatt als separate Zeilen

11

Während unseres letzten wöchentlichen Treffens hat eine Person, die keine Hintergrunderfahrung in der Datenbankverwaltung hat, folgende Frage aufgeworfen:

"Gibt es ein Szenario, das das Speichern von Daten in einer Zeile (Zeichenfolge) anstelle mehrerer Zeilen rechtfertigt?"

Nehmen wir eine Tabelle countryStatesan, in der die Bundesstaaten eines Landes gespeichert werden sollen. Ich werde die USA für dieses Beispiel verwenden und der Faulheit halber nicht alle Staaten auflisten.

Dort hätten wir zwei Spalten; einer rief an Countryund der andere rief an States. Wie hier besprochen und in der Antwort von @ srutzky vorgeschlagen , PKist dies der Code, der durch ISO 3166-1 alpha-3 definiert ist .

Unser Tisch würde so aussehen:

+---------+-----------------------+-------------------------------------------------------+
| Country | States                | StateName                                             |
+---------+-----------------------+-------------------------------------------------------+
| USA     | AL, CA, FL,OH, NY, WY | Alabama, California, Florida, Ohio, New York, Wyoming |
+---------+-----------------------+-------------------------------------------------------+

Als er einem befreundeten Entwickler dieselbe Frage stellte, sagte er, dass dies aus Sicht der Datenverkehrsgröße nützlich sein könnte, aber nicht, wenn wir diese Daten manipulieren müssen. In diesem Fall müsste der Anwendungscode eine Intelligenz enthalten, die diese Zeichenfolge in eine Liste umwandeln könnte (sagen wir, dass die Software, die Zugriff auf diese Tabelle hat, ein Kombinationsfeld erstellen muss).

Wir kamen zu dem Schluss, dass dieses Modell nicht sehr nützlich ist, aber ich wurde misstrauisch, dass es einen Weg geben könnte, dies nützlich zu machen.

Ich möchte fragen, ob einer von Ihnen so etwas bereits auf eine Weise gesehen, gehört oder getan hat, die wirklich funktioniert .

Doch menschlich
quelle
Stellen Sie sich nun vor, Sie haben eine zweite Tabelle, "Verkäufe", die Daten für jeden Verkauf zusammen mit dem Statuscode enthält, in dem der Verkauf stattgefunden hat. Wie würden Sie eine Abfrage schreiben, die einen Bericht mit Spalten generiert (StateName, TotalSalesAmount)? Schwer, oder?
Zgguy
Genau. Ich stimme diesem Modell auch nicht zu. Wir bleiben an jedem Punkt hängen, an dem wir Daten jeglicher Art (oder nützliche Daten, wenn Sie so wollen) wiederherstellen müssen.
Human_AfterAll
Ein mögliches Szenario könnte das Speichern von Variablen sein. Shop a;b;c, verwenden Sie das vordere Ende der Zeichenfolge analysieren Sie dann erhalten a, b, cund tragen auf der Ausführung etwas mit ihnen zu tun, vielleicht ?. Ich glaube, es könnte auf diese Weise zu einem bestimmten Bedürfnis passen ... Beim zweiten Gedanken, nein. Sie können jederzeit IDs speichern, Ihre Tabellen verbinden und eine verkettete Zeichenfolge erstellen, um Inhalte an die FE zu senden ...
Nelz
Um fair zu sein (zumindest für mich ;-), schlug ich vor, in dieser anderen Antwort die 2- stelligen Ländercodes zu verwenden :-) .
Solomon Rutzky
2
Beachten Sie, dass niemand Bedenken hat, den Wert "Alabama" in einer Spalte zu speichern, anstatt eine separate Tabelle mit den Spalten STATE, N & C für "Der Name des Status STATE hat das N-te Zeichen C" zu haben. Weil entweder 1. wir nicht beabsichtigen, nach Zeichen von Namen zu fragen, oder 2. es uns nichts ausmacht, eine Funktion NTH_CHAR (N, S) aufzurufen, die "das N-te Zeichen der Zeichenfolge S" in jeder Zeile mit einem Namen zurückgibt, wenn wir dies tun . (Vs JOIN und andere Vergleichsoperatoren, die einige dieser Zeilen über die zusätzliche Tabelle entfernen.) Das Gleiche gilt für Ganzzahlen und NTH_DIGIT (N, I). Es ist immer ein Urteil darüber, was in einer bestimmten Datenbank relational atomar ist.
Philipxy

Antworten:

13

Zunächst ist der aktuelle Fragentitel, der sich auf "Speichern von Daten als Zeichenfolge anstelle von Spalten" bezieht, etwas verwirrend. Wenn Sie davon sprechen, Daten als Zeichenfolgen anstelle von etwas anderem zu speichern, bezieht sich dies normalerweise auf die Serialisierung aller Daten in ein Zeichenfolgenformat anstelle eines richtigen / starken Datentyps (z . B. INToder DATETIME). Wenn Sie jedoch nach dem Speichern von Daten als mehrere Werte in einem einzelnen Feld im Gegensatz zu separaten Zeilen fragen, ist dies etwas anders. Und um fair zu sein, während das Verketten von Werten mit Strings am einfachsten ist, kann es auch mit INTund BINARYTypen gemacht werden, entweder durch Bitmaskierung oder auf ähnliche Weise, indem bestimmte Positionen mit unterschiedlichen Bedeutungen reserviert werden. Da die zweite Interpretation das ist, worüber tatsächlich gefragt wird, basierend auf dem Text der Frage, wollen wir das ansprechen.

Mit einem Wort: Nein. Wenn Sie tatsächliche Datenpunkte speichern, verursacht dies nur Schmerzen (in Bezug auf Code und Leistung), da dies unnötige Komplikationen darstellt. Wenn es sich um einen Wert handelt, der immer nur als einzelne Einheit gespeichert, als einzelne Einheit aktualisiert und niemals in der Datenbank zerlegt wird, kann dies in Ordnung sein, da dies in etwa dem Speichern eines Bildes oder einer PDF-Datei entspricht. Andernfalls wird jeder Versuch, die Daten zu analysieren, unter Verwendung von Indizes ungültig (z. B. unter Verwendung von LIKE '%something%'oder CHARINDEXoder PATINDEXoder oder SUBSTRINGusw.).

Wenn Sie separate Werte in einem einzelnen Feld einer einzelnen Zeile speichern müssen, gibt es dafür geeignetere Methoden: XML oder JSON. Dies sind analysierbare Formate ( XML / JSON ) und XML kann sogar indiziert werden . Idealerweise werden diese Daten jedoch in richtig eingegebenen Feldern gespeichert, damit sie wirklich nützlich sind.

Und bitte vergessen Sie nicht, dass der Zweck eines RDBMS darin besteht, Daten so zu speichern, dass sie im Rahmen der ACID- Konformität so effizient wie möglich abgerufen und bearbeitet werden können. Das Abrufen verketteter Werte ist schlecht genug, da die Werte zuerst analysiert werden müssen, und das ist nicht indizierbar. Manipulieren bedeutet jedoch häufig, den gesamten Blob zu ersetzen, um nur einen Teil davon zu aktualisieren (vorausgesetzt, es gibt kein Muster, das für eine Funktion verwendet werden kann). Der XML-Datentyp ermöglicht zumindest XML-DML für vereinfachte Aktualisierungen, obwohl diese immer noch nicht so schnell sind wie eine einfache Aktualisierung ordnungsgemäß modellierter Daten.REPLACE

In einem Szenario wie dem in der obigen Frage gezeigten können Sie diese Werte nicht miteinander verknüpfen, indem Sie alle StateCodes miteinander verketten.

Und was ist, wenn sich die Geschäftsanforderungen im Laufe der Zeit ändern und Sie zusätzliche Eigenschaften dieser Elemente verfolgen müssen? Was ist in Bezug auf "Staaten" mit den Hauptstädten oder der Bevölkerung oder einer Sortierreihenfolge oder irgendetwas anderem? Richtig als Zeilen gespeichert, können Sie weitere Spalten für zusätzliche Eigenschaften hinzufügen. Sicher, Sie können mehrere Ebenen von analysierbaren Daten haben, wie zum Beispiel, |StateCode,Capital,Population |StateCode,Capital,Populate|...aber hoffentlich kann jeder sehen, dass das Problem exponentiell außer Kontrolle gerät . Natürlich lässt sich dieses spezielle Problem mit den XML- und JSON-Formaten ziemlich leicht lösen, und das ist ihr Wert, wie oben erwähnt. Sie benötigen jedoch noch einen sehr guten Grund, um eines dieser beiden Elemente als anfängliches Modellierungsmittel zu verwenden, da keines davon jemals so effizient sein wird wie die Verwendung diskreter Felder in separaten Zeilen.

Solomon Rutzky
quelle
9

Ich habe so etwas tatsächlich für einen sehr begrenzten Zweck verwendet. Wir haben eine Tabelle mit Headern für Ausgabedateien erstellt. Sie wurden speziell konstruiert und waren meist nur die Spaltenüberschriften, aber nicht ganz. Die Daten sahen also ungefähr so ​​aus

OutputType   OutputHeader
PersonalData Name|Address|City|State|Zip
JobInfo      Name|JobName|JobTitle

Im Wesentlichen sah es so aus, als wäre es eine begrenzte Liste. Und in gewisser Weise war es. Aber für unsere Zwecke war es eine einzelne lange Saite.

Das ist der Trick hier. Wenn Sie nie vorhaben, die Liste zu analysieren, lohnt es sich, die Liste zu speichern. Wenn Sie die Liste jedoch analysieren müssen oder müssen, lohnt sich der zusätzliche Platz und die zusätzliche Zeit, um sie aufzuteilen und in separaten Zeilen zu speichern.

Kenneth Fisher
quelle
1

Ich habe es einmal mit einem eher kleinen Tisch benutzt, zum Beispiel:

CREATE TABLE t1 (
  ID number,
  some_feature   varchar2(100),
  valid_channels  varchar2(100));

CREATE TABLE channel_def (
  channel varchar2(100));

Und dann Werte speichern CRM,SMS,SELF-CAREin valid_channel.

Die gesamte Tabelle enthält ungefähr 10 Datensätze. valid_channelenthält Werte, die sich eigentlich in einer Verknüpfungstabelle befinden sollten, die die Viele-zu-Viele-Beziehung darstellt. Der Tisch t1wird nicht intensiv genutzt, deshalb haben wir uns entschlossen, diesen Weg zu gehen. An dieser Entscheidung war jedoch etwas Politik beteiligt (siehe unten).

Aber im Allgemeinen vermeide ich es, es ist nicht 3NF.

Der Ort, an dem ich arbeite, hat derzeit Dutzende solcher Spalten überall. Ihre Rechtfertigung ist, dass es ihre Abfragen einfacher macht: Anstatt drei Tabellen mithilfe der Verknüpfungstabelle zu verbinden, können sie direkt zur Definitionstabelle mit gehen LIKE. Z.B

SELECT * 
  FROM t1 
 INNER JOIN channel_def cd
    ON ','||t1.valid_channels||',' LIKE '%,'||cd.channel||',%';

Horrible + unter Oracle deaktiviert die Verwendung von Index aufgrund des Starts '%,'.

Robotron
quelle
Was wäre langsamer: LIKEoder eine einfache Verbindung?
Human_AfterAll
Es ist am besten, einen Join für eine Spalte zu haben, die indiziert ist oder zumindest eine referenzielle Einschränkung (FK) aufweist. Darüber hinaus werden Verknüpfungen normalerweise für eine PK der anderen Tabelle ausgeführt, die standardmäßig indiziert ist (zumindest für Oracle). Wenn Sie nach dem vorliegenden Fall fragen (siehe oben), würde der Ausführungsplan höchstwahrscheinlich sagen, dass es der gleiche war, da es sich um einen kleinen Tisch handelte.
Robotron
@Human_AfterAll das LIKEwäre langsamer, insbesondere wenn die Daten richtig modelliert sind, um ein TINYINTPK-Feld in zu verwenden channel_def. Dann muss nur noch ein einziges Byte zwischen den beiden Tabellen verglichen werden. Hier muss die Zeichenfolge zeichenweise analysiert werden (zumindest bis die Bedingung erfüllt ist), und es wird eine Suche ohne Berücksichtigung der Groß- und Kleinschreibung durchgeführt (basierend auf der angegebenen Tabelle def wird keine verwendete Kollatierung _BIN2angezeigt). Dadurch werden Indizes auch in SQL Server ungültig. Ich habe dies in meiner Antwort angesprochen, indem ich sagte, dass beim Parsen keine Indizes verwendet werden können. Ich habe gerade meine Antwort aktualisiert, um es klarer zu machen.
Solomon Rutzky
1
@Human_AfterAll Ich würde sagen, dass diese Modellierungsentscheidung auf einem Mangel an Erfahrung und Wissen (und manchmal auf Faulheit) beruht . Ein zusätzlicher JOIN ist alles, was gespeichert wird, aber was geopfert wird, ist die Fähigkeit zum Fremdschlüssel, die verhindern würde, dass völlig falsche Daten eingehen (selbst wenn es nicht mit der LIKEKlausel übereinstimmt und ungerade Ergebnisse liefert, kann es dennoch andere Probleme verursachen oder zumindest das Debuggen erschweren / verlängern). Dies valid_channelserschwert auch die Aktualisierung des Feldes. Das soll nicht heißen, dass dies nicht funktioniert, es gibt einfach keinen guten Grund dafür.
Solomon Rutzky
"Mangel an Erfahrung" - was am schlimmsten ist, dass diese spezielle Designentscheidung von einem leitenden Mitarbeiter auferlegt wurde ...
Robotron
1

Dies wurde hier auf SE gemacht. Wie Marc Gravell schreibt :

... Nach einigem Überlegen und Überlegen haben wir uns für eine durch Pipes (Balken) begrenzte natürliche Darstellung mit führenden / nachfolgenden Pipes entschieden, sodass ".net c #" einfach zu "| .net | c # |" wird. Das hat Tugenden:

  • sehr einfach zu analysieren
  • Das Aktualisieren und Entfernen von Tags in großen Mengen kann durch einfaches Ersetzen erfolgen (einschließlich der Pipes, um das Ersetzen von Übereinstimmungen mit mittleren Tags zu vermeiden).
  • ...

Dieses "neue Format" war der nächste Schritt gegenüber dem "alten Format", das etwas anders war und ausgewählt wurde, um die SQL Server-Volltextsuchfunktion zu verwenden. Daher sind einige der Vorteile nicht relevant, wenn Sie es von Grund auf neu ausführen.

Vermutlich haben sie die Sache sowohl aus Arbeits- als auch aus Leistungsgründen nicht vollständig normalisiert.

Eugene Ryabtsev
quelle
0

Ein möglicher Hauptvorteil der Verwendung von Zeichenfolgen und anderen Datentypen besteht darin, sie mithilfe der SQLCLR von SQL Server an C #, C, C ++ (usw.) zu senden, wenn möglicherweise eine reine Leistung erforderlich ist. Sie können sogar eine Ansicht oder eine gespeicherte Prozedur erstellen, um relationale Daten nicht relational darzustellen - wie Sie es in Ihrem obigen Beispiel zu diesem Zweck getan haben.

Siehe dieses Beispiel:

http://aboutsqlserver.com/2013/07/22/clr-vs-t-sql-performance-considerations/

per Wikipedia: SQL CLR oder SQLCLR (SQL Common Language Runtime) ist eine Technologie zum Hosten der Microsoft .NET Common Language Runtime Engine in SQL Server. Mit SQLCLR kann verwalteter Code von der Microsoft SQL Server-Umgebung gehostet und ausgeführt werden.

Stachel
quelle
2
Hallo. Können Sie hier bitte näher darauf eingehen? Ich bin mir nicht sicher, wie dies von Vorteil ist, wenn Daten auf nicht traditionelle Weise gespeichert werden. Wenn überhaupt, ist es ein Vorteil von SQLCLR, mit alternativen Datenformaten besser umgehen zu können, wenn diese vorhanden sein müssen. Dies ist jedoch kein Grund, ein alternatives Datenformat zu bevorzugen. Daher glaube ich wirklich nicht, dass dies die Frage beantwortet.
Solomon Rutzky
Der Artikel-Link erklärt die Vorteile mit den Vor- und Nachteilen. Außerdem erwähnte ich das relationale Speichern der Daten und zum Zwecke der CLR-Konvertierung in nicht relationale Daten mit einer Ansicht oder einer gespeicherten Prozedur. Ihre Frage lautete: "Gibt es ein Szenario, in dem das Speichern von Daten in einer Zeile (Zeichenfolge) anstelle mehrerer Zeilen gerechtfertigt ist?" Und meine Antwort war ja, obwohl ich eine Ansicht oder eine gespeicherte Prozedur für die Interaktion mit der CLR bevorzuge.
Sting
0

Meiner Meinung nach wäre die Antwort nein. Ich habe diesen Ansatz nicht verwendet und würde ihn vermeiden - ich kann mir keinen Grund vorstellen, warum ich diesen Weg gehen würde. Sie neigen mit einem Array zur Welt von JSON / NoSQL.

In einer früheren Rolle hatten wir ähnliche Entwurfsentscheidungen, wobei das Architektenteam ein "Daten" -Feld haben wollte, das abgegrenzt und dann in eine Binärdatei konvertiert wurde. Wir sind diesen Weg am Ende aus mehreren Gründen nicht gegangen.

Wenn Sie sich dieser Art von Daten anschließen müssten, wäre dies eine hässliche Erfahrung. Das Aktualisieren einzelner Elemente der Zeichenfolge wäre ebenfalls unangenehm.

Clive Strong
quelle