Laden...

Lieber eine oder zwei Tabellen (Join oder Null-Felder)

Erstellt von Christoph K. vor 8 Jahren Letzter Beitrag vor 8 Jahren 2.338 Views
Christoph K. Themenstarter:in
821 Beiträge seit 2009
vor 8 Jahren
Lieber eine oder zwei Tabellen (Join oder Null-Felder)

verwendetes Datenbanksystem: MSSQL

Hallo zusammen,
ich habe eine Datenbankstruktur, in welcher ich eine Tabelle habe, in der ziemlich viele Daten optional sind.
Daher habe ich beim ursprünlichen Design der Datenbank, die optionalen Daten in eine andere Tabelle ausgelagert. Es besteht zwischen den beiden Tabellen nun eine 1 zu {0,1} - Verknüpfung.

Nun ist es jedoch sehr nervig, die Tabellen immer zu joinen und ich überlege, ob ich die optionalen Daten nicht mit in die ursprüngliche Tabelle mit aufnehme. Zusätzlich denke ich, dass ich durch den nicht mehr benötigten Join vielleicht etwas Geschwindigkeit gewinnen könnte.

Meine Fragen sind nun:
Was sprich generell dafür/dagegen?
Wie hoch ist der zusätzliche Speicherbedarf für einen Eintrag in der Tabelle, wenn die optionalen Felder gar nicht belegt werden (NULL sind).

Danke und Gruß

502 Beiträge seit 2004
vor 8 Jahren

Zusätzlich denke ich, dass ich durch den nicht mehr benötigten Join vielleicht etwas Geschwindigkeit gewinnen könnte. Das ist mehr als wahrscheinlich...

Was sprich generell dafür/dagegen?

Grundsätzlich sind erst mal beide Ansätze legitim. Wenn's wirklich nur darum geht, dass Spalten NULL sind, würde ich persönlich in den allermeisten Fällen dazu tendieren, das in eine Tabelle zu packen. Das kann aber durchaus auch anders sein, wenn es wirklich extrem viele Spalten werden oder wenn die genannten JOINS recht selten nötig sind, oder, oder...

Wie hoch ist der zusätzliche Speicherbedarf für einen Eintrag in der Tabelle, wenn die optionalen Felder gar nicht belegt werden (NULL sind).Danke und Gruß

Das hängt von den Spalten-Datentypen ab. Wenn Du irgendwelche BLOB Daten (z.B. IMAGE oder auch navarchar(max) verwendest oder auch "sehr kleine" Datentypen (bit, int,...) dann ist das denke ich (im Allgemeinen) sehr leicht zu verschmerzen, was das an Speicherverbrauch kostet. Jedenfalls wenn man die ansonsten u.U. ständignötigen JOINS mit in betracht zieht. Denn Performance ist meistens deutlich wichtiger als ein bisschen mehr belegter Plattenplatz. Wenn Du allerdings sehr viele Spalten mit "festen Speicherverbrauch" (das vom SQL Server verwendete physische Layout der Tabelle ist hier ausschlaggebend) hast (meistens trifft sowas z.B. bei Spalten mit nvarchar(x), mit x irgendwo im Hunderterbereich zu), dann könnte das schon deutlich ins Gewicht fallen. Ich persönlich denke aber, dass das nur in sehr speziellen Randbedingungen eine Rolle spielen dürfte...

Du könntest ja mal ein (ggf. vereinfachtes) CREATE TABLE Statement für die beiden Varianten posten, dann kann Dir hier evtl. auch eine etwas fundiertere Aussage geliefert werden. Denn Aussagen wie "...ziemlich viele..." sind immer relativ :evil:
Und: Eine zumindest ungefähre Einschätzung für die Anzahl der Datensätze ist auch hilfreich!

Bart Simpson

Praxis ist wenn alles funktioniert und keiner weiss warum.
Theorie ist wenn man alles weiss, aber nichts funktioniert.

Bei uns wird Theorie und Praxis vereint: Nichts funktioniert und keiner weiss warum...

B
112 Beiträge seit 2008
vor 8 Jahren

verwendetes Datenbanksystem: MSSQL

Hallo zusammen,
ich habe eine Datenbankstruktur, in welcher ich eine Tabelle habe, in der ziemlich viele Daten optional sind.

Bist Du sicher, dass eine SQL-Datenbank für Deine Daten das Mittel der Wahl ist?

Daher habe ich beim ursprünlichen Design der Datenbank, die optionalen Daten in eine andere Tabelle ausgelagert. Es besteht zwischen den beiden Tabellen nun eine 1 zu {0,1} - Verknüpfung.

Nun ist es jedoch sehr nervig, die Tabellen immer zu joinen und ich überlege, ob ich die optionalen Daten nicht mit in die ursprüngliche Tabelle mit aufnehme. Zusätzlich denke ich, dass ich durch den nicht mehr benötigten Join vielleicht etwas Geschwindigkeit gewinnen könnte.

Andererseits handelst Du Dir zusätzliche Komplexität ein: Abfragen müssen die NULL-Werte berücksichtigen. Und sind bei einem Satz entweder alle optionalen Felder leer oder keins von ihnen? Dann muss jede Anwendung dafür sorgen, dass das immer richtig herüberkommt. Scheint mir potentiell schwieriger als wenn ein "optionaler Satz" grundsätzlich entweder erzeugt wird, mit korrekten Werten, oder ganz wegbleibt.

Christoph K. Themenstarter:in
821 Beiträge seit 2009
vor 8 Jahren

@bb1898: Das ist generell der Fall, bzw. muss in der Anwendung bis dato eh schon untersucht werden.

@Bart Simpson

Vielen Dank für deine Hilfe, dass Statement für die "optionale" Table sieht wie folgt aus:



CREATE TABLE [dbo].[OnPagePages](
	[Id] [int] IDENTITY(1,1) NOT NULL,
	[UrlId] [int] NOT NULL,
	[Title] [nvarchar](max) NULL,
	[TitleLength] [int] NULL,
	[TitleWidth] [int] NULL,
	[Description] [nvarchar](max) NULL,
	[DescriptionType] [nvarchar](max) NULL,
	[DescriptionLength] [int] NULL,
	[SizeInBytesAggregated] [int] NULL,
	[NumberOfWords] [int] NULL,
	[NumberOfDifferentWordsWithoutStopwords] [int] NULL,
	[TextToCodeRatio] [float] NULL,
	[NumberOfExternalCssFiles] [int] NULL,
	[NumberOfExternalJavascriptFiles] [int] NULL,
	[CanonicalPageId] [int] NULL,
	[CanonicalEqualityTypeId] [int] NULL,
	[PageRank] [float] NULL,
	[RobotsFollow] [bit] NULL,
	[RobotsIndex] [bit] NULL,
	[Language] [nvarchar](max) NULL,
	[Author] [nvarchar](max) NULL,
	[NumberOfH1] [int] NULL,
	[NumberOfH2] [int] NULL,
	[NumberOfH3] [int] NULL,
	[NumberOfH4] [int] NULL,
	[NumberOfH5] [int] NULL,
	[NumberOfH6] [int] NULL,
	[NumberOfJavascriptBlocks] [int] NULL,
	[NumberOfCssBlocks] [int] NULL,
	[NumberOfImages] [int] NULL,
	[NumberOfOutgoingLinks] [int] NULL,
	[NumberOfOutgoingExternalLinks] [int] NULL,
	[NumberOfOutgoingBrokenLinks] [int] NULL,
	[NumberOfOutgoingNoFollowLinks] [int] NULL,
	[NumberOfOutgoingInternalNoFollowLinks] [int] NULL,
	[NumberOfOutgoingExternalFollowLinks] [int] NULL,
 CONSTRAINT [PK_OnPagePage] PRIMARY KEY CLUSTERED 
(
	[Id] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY] TEXTIMAGE_ON [PRIMARY]

502 Beiträge seit 2004
vor 8 Jahren

Zum einen muss ich bb1898's Anmerkung zustimmen, dass Du Dir evtl. nochmal generelle Gedanken bezüglich des "DB-Designs" bzw. der "DB-Egnine" machen solltest.

Um beim Thema zu bleiben und auf Deine Tabelle Bezug zu nehmen: Wenn das alles ist, würde ich persönlich nicht mal drüber nachdenken, das in zwei Teile zu zerlegen. Die paar (im wesentlichen) INT-Werte sind marginal im Hinblick auf den Speicherverbrauch. Die BLOBs werden vom SQL-Server sowieso "ausgelagert", also dürfte das keinen großen Overhead erzeugen...
Wenn Du also nicht gerade jenseits der X-Millionen Datensätze bist, dann lautet meine Empfehlung definitiv: Eine Tabelle für alles.

Praxis ist wenn alles funktioniert und keiner weiss warum.
Theorie ist wenn man alles weiss, aber nichts funktioniert.

Bei uns wird Theorie und Praxis vereint: Nichts funktioniert und keiner weiss warum...

Christoph K. Themenstarter:in
821 Beiträge seit 2009
vor 8 Jahren

@Bart Simpsons:

Also aktuelle rechne ich mit ca. 10 Mio Datensätzen.
Weißt du wie sich der SQL-Server bezüglich der NULL(able) Datensätze verhält?
Reserviert er hierfür überhaupt irgendwas an Speicher?

Ich habe gerade mal ein paar Felder der Ursprünglichen Tabelle hinzugefügt. Der Speicherplatzverbrauch im Management-Studio ist hierdurch allerdings für die benötigen Datenspeicher geringer(!) geworden. Ich denke jedoch, dass er die Neustrukturierung ebenfalls zur Speicheroptimierung genutzt hat und der Wert daher nicht wirklich aussagekräftig ist.

Danke & Gruß

502 Beiträge seit 2004
vor 8 Jahren

Also aktuelle rechne ich mit ca. 10 Mio Datensätzen.

Damit komm ich auf einen "zusätzlichen" Speicherbedarf von ca. 1,5 GB (plus das, was die BLOBs tatsächlich benötigen - aber das brauchst Du ja in beiden Varianten)... Stellt das wirklich ein Problem dar? Das ist in meiner täglichen Arbeit eher zu vernachlässigen - aber das mag natürlich in Deinem Anwendungsfall anders sein...

Weißt du wie sich der SQL-Server bezüglich der NULL(able) Datensätze verhält?
Reserviert er hierfür überhaupt irgendwas an Speicher?

Das sind Details die u.a. von der Version abhängen - aber hier ist die Doku oder die MSDN Dein Freund...

Bart Simpson

Praxis ist wenn alles funktioniert und keiner weiss warum.
Theorie ist wenn man alles weiss, aber nichts funktioniert.

Bei uns wird Theorie und Praxis vereint: Nichts funktioniert und keiner weiss warum...

Christoph K. Themenstarter:in
821 Beiträge seit 2009
vor 8 Jahren

Damit komm ich auf einen "zusätzlichen" Speicherbedarf von ca. 1,5 GB (plus das, was die BLOBs tatsächlich benötigen - aber das brauchst Du ja in beiden Varianten)... Stellt das wirklich ein Problem dar? Das ist in meiner täglichen Arbeit eher zu vernachlässigen - aber das mag natürlich in Deinem Anwendungsfall anders sein...

Nein, das stellt kein Problem dar, ich habe 1TB für die DB eingeplant.
Von daher werde ich deinem Rat folgen und die beiden Tabellen zusammenführen.

Danke nochmal für die Hilfe!

16.842 Beiträge seit 2008
vor 8 Jahren

Also wenn Du 1 TB eingeplant ist (nur mal als vergleich: 1 TB ist das aktuelle Maximum, was Azure SQL zulässt (P11)) ist das definitiv nicht mehr wenig.
Dahingehend solltest Du nicht nur das DB Design überdenken; sehr wahrscheinlich musst Du das in dieser Region sogar.

PS: eigentlich, so wie Du das beschreibst , passt NoSQL (zB MongoDB) genau für diesen Anwendungsfall wie die Faust aufs Auge.

W
198 Beiträge seit 2008
vor 8 Jahren

Solltest Du doch mit zwei Tabellen weiterarbeiten wollen und die 'nervigen' joins vermeiden wollen, solltest Du Dir vllt. ein View anlegen, in dem Du die beiden Tabellen zusammenfasst.

A
764 Beiträge seit 2007
vor 8 Jahren

Zusätzlich denke ich, dass ich durch den nicht mehr benötigten Join vielleicht etwas Geschwindigkeit gewinnen könnte.
Das ist mehr als wahrscheinlich...

Frage: Ist das bei indizierten 1 zu 1 Beziehungen tatsächlich so?

3.003 Beiträge seit 2006
vor 8 Jahren

Schwierig, darüber belastbare Zahlen zu finden. Ich würde intuitiv mit "ja" antworten, weil im Prinzip dasselbe Ergebnis geliefert, aber bei der Abfrage eben ein zusätzliches join anfällt - aber Intuition würde ich selbst kaum als Argument gelten lassen 😉. Im Prinzip dürfte die vorgeschlagene Lösung mit einem View bei so einer eher mittelgroßen Menge an Daten empfehlenswert sein.

LaTino

"Furlow, is it always about money?"
"Is there anything else? I mean, how much sex can you have?"
"Don't know. I haven't maxed out yet."
(Furlow & Crichton, Farscape)

P
1.090 Beiträge seit 2011
vor 8 Jahren

Also den Join, solltest du in deinem DAL nur einmal schreiben. Und da du grundlegend deine Abfragen eher so schreiben solltest, das sie dir nur die Daten zurück liefern, die du brauchst. Ist es eher eine frage an die Statistik.

Wenn ich in 99% der Fälle die Daten nicht brauche (die Werte NULL sind) ist es sicher besser eine eigene Tabelle dafür anzulegen. Wenn ich sie in 99% der Fälle brauche, ist es besser sie mit in die Tabelle zu packen.

Grundlegend sollte man erst mal beim Datenbank Desinge darauf achten die Tabellen zu Normalisieren. Denoralisieren kann man dann aus Performance Gründen.

Bei Performance gilt aber im allgemeinen Messen. Alles andere sind meist nur Vermutungen.

Sollte man mal gelesen haben:

Clean Code Developer
Entwurfsmuster
Anti-Pattern