Share via


Normalisierung

Der logische Entwurf der Datenbank, einschließlich der Tabellen und der Beziehungen zwischen ihnen, stellt das Kernstück einer optimierten relationalen Datenbank dar. Ein durchdachter logischer Datenbankentwurf kann die Grundlage für eine optimale Datenbank- und Anwendungsleistung bilden. Ein weniger guter Entwurf kann die Leistung des gesamten Systems beeinträchtigen.

Zur Normalisierung eines logischen Datenbankentwurfs gehört das Verwenden formaler Methoden, um die Daten in mehrere verbundene Tabellen aufzuteilen. Mehrere schmale Tabellen mit weniger Spalten sind das Merkmal einer normalisierten Datenbank. Wenige breite Tabellen mit einer größeren Anzahl von Spalten kennzeichnen eine nicht normalisierte Datenbank.

Durch eine gemäßigte Normalisierung wird häufig eine Leistungsverbesserung erzielt. Stehen sinnvolle Indizes zur Verfügung, kann der Abfrageoptimierer von SQL Server schnelle und effiziente Joins zwischen Tabellen auswählen.

Zu den Vorteilen der Normalisierung gehören Folgende:

  • Schnellere Sortierung und Indexerstellung.

  • Eine größere Anzahl gruppierter Indizes. Weitere Informationen finden Sie unter Richtlinien für den Entwurf gruppierter Indizes.

  • Schmalere und kompaktere Indizes.

  • Weniger Indizes pro Tabelle Dies verbessert die Leistung von INSERT-, UPDATE- und DELETE-Anweisungen.

  • Weniger NULL-Werte und geringere Gefahr von Inkonsistenzen. Auf diese Weise wird die Datenbank kompakter.

Je größer die Normalisierung, desto größer ist die Anzahl und Komplexität der Joins, die für das Abrufen von Daten erforderlich sind. Zu viele komplexe relationale Joins zwischen zu vielen Tabellen können die Leistung negativ beeinflussen. Eine Normalisierung in gemäßigtem Umfang enthält häufig nur wenige, regelmäßig ausgeführte Abfragen, die Joins mit mehr als vier Tabellen verwenden.

In einigen Fällen ist der Entwurf der logischen Datenbank bereits fertig gestellt, und eine komplette Erneuerung ist nicht durchführbar. Doch selbst dann ist es in bestimmten Fällen möglich, eine große Tabelle in kleinere Tabellen aufzuteilen. Erfolgt der Zugriff auf die Datenbank mithilfe gespeicherter Prozeduren, könnte diese Schemaänderung vorgenommen werden, ohne dass Anwendungen davon beeinflusst werden. Andernfalls könnte eine Sicht erstellt werden, die die Schemaänderung vor den Anwendungen verbirgt.

Erhalten einer sorgfältig entworfenen Datenbank

In der Theorie zum Entwurf relationaler Datenbanken identifizieren Normalisierungsregeln bestimmte Attribute, die in einer sorgfältig entworfenen Datenbank vorhanden sein müssen (oder nicht vorhanden sein dürfen). Eine vollständige Erläuterung der Normalisierungsregeln würde den Rahmen dieses Themas sprengen. Es gibt jedoch einige Regeln, die Sie beachten sollten, um einen leistungsfähigen Datenbankentwurf zu erhalten:

  • Eine Tabelle sollte über einen Bezeichner verfügen.

    Die zentrale Regel der Theorie zum Datenbankentwurf besagt, dass jede Tabelle über einen eindeutigen Zeilenbezeichner verfügen sollte. Der eindeutige Zeilenbezeichner ist eine Spalte oder eine Reihe von Spalten, mit deren Hilfe ein einzelner Datensatz von jedem anderen Datensatz in der Tabelle unterschieden werden kann. Jede Tabelle sollte über eine ID-Spalte verfügen, und es können nicht mehrere Datensätze denselben ID-Wert verwenden. Die Spalte oder Spalten, die als eindeutiger Zeilenbezeichner für eine Tabelle dienen, ist bzw. sind der Primärschlüssel der Tabelle. In der AdventureWorks2008R2-Datenbank enthält jede Tabelle eine Identitätsspalte als primäre Schlüsselspalte. VendorID ist z. B. der Primärschlüssel für die Purchasing.Vendor-Tabelle.

  • In einer Tabelle sollten nur Daten für einen einzigen Entitätstyp gespeichert werden.

    Werden zu viele Informationen in einer Tabelle gespeichert, kann dies die effiziente und zuverlässige Verwaltung der Tabellendaten verhindern. In der AdventureWorks2008R2-Beispieldatenbank werden die Kaufauftrags- und Kundeninformationen in separaten Tabellen gespeichert. Obwohl es möglich ist, in einer einzigen Tabelle Spalten zu verwenden, die Informationen sowohl zu einem Kaufauftrag als auch zu dem entsprechenden Kunden enthalten, führt dieser Entwurf zu verschiedenen Problemen. Die Kundeninformationen (Name und Adresse) müssen hinzugefügt und redundant für jeden Kaufauftrag gespeichert werden. Hierdurch wird zusätzlicher Speicherplatz in der Datenbank verwendet. Wenn sich die Kundenadresse ändert, muss diese Änderung für jeden Kaufauftrag vorgenommen werden. Wenn der letzte Kaufauftrag eines Kunden aus der Sales.SalesOrderHeader-Tabelle entfernt wird, gehen außerdem die Informationen für diesen Kunden verloren.

  • In einer Tabelle sollten keine Spalten verwendet werden, die NULL zulassen.

    In Tabellen können Spalten definiert werden, die NULL-Werte zulassen. Ein NULL-Wert zeigt an, dass kein Wert vorhanden ist. In Einzelfällen kann es sinnvoll sein, NULL-Werte zuzulassen, dies sollte jedoch die Ausnahme bleiben. Der Grund liegt darin, dass für diese Spalten eine besondere Verarbeitung erforderlich ist, die die Komplexität von Datenvorgängen vergrößert. Wenn Sie eine Tabelle mit vielen Spalten verwenden, die NULL zulassen, und für viele Zeilen ein NULL-Wert in diesen Spalten gespeichert ist, sollten Sie in Erwägung ziehen, die betreffenden Spalten zu einer gesonderten Tabelle zusammenzufassen und diese dann mit der Primärtabelle zu verknüpfen. Wenn die Daten in zwei getrennten Tabellen gespeichert werden, verfügt die Primärtabelle über einen einfachen Aufbau, und es besteht trotzdem die Möglichkeit, diese Informationen bei Bedarf zu speichern.

  • Eine Tabelle sollte keine wiederkehrenden Werte oder Spalten enthalten.

    Die Tabelle für ein Element in der Datenbank sollte keine Liste mit Werten für eine spezielle Information enthalten. Ein Produkt in der AdventureWorks2008R2-Datenbank kann z. B. von mehreren Lieferanten erworben werden. Wenn in der Production.Product-Tabelle eine Spalte für den Namen des Lieferanten vorhanden ist, ergibt sich ein Problem. Eine Lösung besteht darin, die Namen aller Lieferanten in der Spalte zu speichern. Dann wird es jedoch schwierig, eine Liste der einzelnen Lieferanten anzuzeigen. Eine andere Lösung besteht darin, die Struktur der Tabelle zu ändern und eine weitere Spalte für den Namen des zweiten Lieferanten hinzuzufügen. Bei dieser Struktur könnten jedoch nur die Namen von zwei Lieferanten gespeichert werden. Es muss außerdem eine weitere Spalte hinzugefügt werden, wenn ein Buch über drei Lieferanten verfügt.

    Wenn die Notwendigkeit besteht, eine Liste mit Werten in einer einzigen Spalte zu speichern, oder Sie mehrere Spalten für einen bestimmten Dateneintrag benötigen (z. B. Rufnummer1 und Rufnummer2), sollten Sie erwägen, die doppelt vorhandenen Daten in einer anderen Tabelle zu speichern, die über einen Join zu der Primärtabelle verfügt. Die AdventureWorks2008R2-Datenbank besitzt eine Production.Product-Tabelle für Produktinformationen, eine Purchasing.Vendor-Tabelle für Lieferanteninformationen sowie eine dritte Tabelle, Purchasing.ProductVendor. Diese dritte Tabelle speichert nur die ID-Werte für die Produkte sowie die IDs der Lieferanten dieser Produkte. Dieser Entwurf ermöglicht, dass eine beliebige Anzahl von Lieferanten für ein Produkt gespeichert wird, ohne die Definition der Tabelle ändern zu müssen. Zudem wird kein überflüssiger Speicherplatz für Produkte mit einem einzigen Lieferanten zugeordnet.