Wie Fremdschlüssel-Einschränkungen Ausführungspläne beeinflussen
Für viele Kollegen und Freunde, mit denen ich über Fremdschlüssel und deren Bedeutung für Datenbanken spreche, steht im Vordergrund, dass ein Fremdschlüssel sicherstellt, nur Werte aus einer referenzierten Tabelle zuzulassen. Diese Aussage ist nur bedingt richtig – vielmehr spielt eine Fremdschlüsselbeziehung auch bei Abfragen eine wichtige Rolle, wenn der Abfrage Optimierer seine Arbeit verrichtet.
Was ist eine Fremdschlüssel-Einschränkung?
Unter einer Fremdschlüssel-Einschränkung (Foreign Key Constraint) versteht man eine Kombination von Attributen in einer Tabelle, mit deren Hilfe eine Verknüpfung zwischen den Daten zweier Tabellen erzwungen wird. In einem sogenannten Fremdschlüsselverweis besteht zwischen zwei Tabellen eine Verknüpfung, wenn eine oder mehrere Attribute einer Tabelle (Detailtabelle) auf ein oder mehrere Attribute einer anderen Tabelle (Mastertabelle) verweisen.
Klassische Fremdschlüsselbeziehungen sind z. B. in einem Auftragssystem zu finden, in dem zu Auftragsdetails (Detailtabelle) immer ein Auftragskopf (Mastertabelle) enthalten sein muss. In einer solchen Konstruktion wird das Primärattribut der Mastertabelle (z. B. Auftrag_Id) zum Fremdschlüssel in der Detailtabelle. Neben der erwähnten Durchsetzung von Datenintegritätsregeln kann aber Microsoft SQL Server Fremdschlüssel auch ideal für die Optimierung von Abfragen verwenden, wie die nachfolgende Demonstration zeigt.
Testumgebung für Demonstration
Welche Einflüsse eine Fremdschlüssel-Einschränkung auf die Ausführung von Abfragen haben kann, soll mit dem folgenden Datenmodell demonstriert werden (SQL Server 2012).
Zu verschiedenen Projekten ([dbo].[Projects]) gibt es eine Vielzahl von Projektmitgliedern ([dbo].[ProjectMembers]). Beide Tabellen stehen in einer 1:n-Abhängigkeit zueinander. Damit in die Tabelle [dbo].[ProjectMembers] keine Projektnummern eingetragen werden können, die nicht in [dbo].[Projects] existieren, wird eine Fremdschlüssel-Beziehung zwischen beiden Tabellen implementiert. Gleiches gilt für die Tabelle [dbo].[Employees]. Das anschließende T-SQL-Script erzeugt die oben beschriebene Struktur.
-- Mitarbeiter
CREATE TABLE dbo.Employees
(
Id int NOT NULL IDENTITY (1, 1),
FirstName varchar(64) NOT NULL,
LastName varchar(64) NOT NULL,
HiredAt date NOT NULL,
FiredAt date NULL,
CONSTRAINT pk_Employees_Id PRIMARY KEY CLUSTERED (Id)
);
-- Projekte
CREATE TABLE dbo.Projects
(
Id int NOT NULL IDENTITY(1, 1),
ProjectName varchar(64) NOT NULL,
ProjectStart date NOT NULl DEFAULT (getdate()),
ProjectFinish date NULL,
ProjectLead int NOT NULL,
CONSTRAINT pk_Projects_Id PRIMARY KEY CLUSTERED (Id),
CONSTRAINT fk_Projects_ProjectLead FOREIGN KEY (ProjectLead)
REFERENCES dbo.Employees (Id)
);
-- Projektmitarbeiter
CREATE TABLE dbo.ProjectMembers
(
Project_Id int NOT NULL,
Employee_Id int NOT NULL,
StartDate date NOT NULL,
FinishDate date NULL,
CONSTRAINT pk_ProjectMembers PRIMARY KEY CLUSTERED
(
Project_Id,
Employee_Id
),
CONSTRAINT fk_ProjectMembers_Project_Id FOREIGN KEY (Project_Id)
REFERENCES dbo.Projects (Id),
CONSTRAINT fk_ProjectMembers_Employee_Id FOREIGN KEY (Employee_Id)
REFERENCES dbo.Employees (Id)
);
Demonstration
Der Ausführungsplan der folgenden Abfrage zeigt, wie “optimal” Microsoft SQL Server Ermittlung von geeigneten Ausführungsplänen vorgeht:
SELECT p.Id,
p.ProjectName,
p.ProjectStart AS Project_StartDate,
p.ProjectFinish AS Project_Finish,
pm.StartDate AS Employee_StartDate,
pm.FinishDate AS Employee_FinishDate
FROM dbo.Projects p INNER JOIN dbo.ProjectMembers pm
ON (p.Id = pm.Project_Id) INNER JOIN dbo.Employees e
ON (pm.Employee_Id = e.Id);
Die Abfrage ermittelt neben den Projektdaten (Name, Start und Ende) ebenfalls die Start- und Endzeiten für die einzelnen Mitarbeiter. Die Abfrage selbst verwendet alle drei Tabellen, die in einer unmittelbaren Abhängigkeit zueinander stehen. Der Ausführungsplan für diese Abfrage gestaltet sich aber überraschender Weise wie folgt:
Obwohl in der auszuführenden Abfrage drei Tabellen verwendet werden, nimmt Microsoft SQL Server ausschließlich die Tabellen [dbo].[Projects] und [dbo].[ProjectMembers] für die Ausführung der Abfrage. Grund für dieses Ergebnis ist ein Prozessschritt innerhalb der Optimierungsphasen von Microsoft SQL Server bei der Suche nach einem optimalen Ausführungsplan – Simplification!
Bei “Simplification” versucht Microsoft SQL Server, den “Query Tree” auf einfache Formen zu reduzieren. um den Optimierungsprozess als solchen zu vereinfachen. Beispielsweise werden Subqueries in JOINS gewandelt oder redundante JOINS werden entfernt; widersprüchliche Anweisungen werden entfernt, …! Wer sich tiefer mit dieser Materie beschäftigen möchte, dem sei das Buch “Inside the SQL Server Query Optimizer” von Benjamin Nevarez sehr ans Herz gelegt.
Im Ergebnis der Abfrage werden Attribute der Tabellen [dbo].[Projects] und [dbo].[ProjectMembers] ausgegeben. Warum also sollte Microsoft SQL Server eine Prüfung der Daten aus [dbo].[Employees] vornehmen? Eine Prüfung ist obsolet, da beide Relationen durch eine Fremdschlüssel-Einschränkung miteinander in Beziehung stehen. Durch die Fremdschlüsselbeziehung wird gewährleistet, dass sich im Attribut [Employee_Id] von [dbo].[ProjectMembers] keine Daten befinden können, die nicht in [dbo].[Employees] existieren.
Gleiche Abfrage – keine Fremdschlüssel-Einschränkung
Um den – gravierenden - Unterschied zu zeigen, wird die Fremdschlüssel-Einschränkung vor der nächsten Ausführung der Abfrage deaktiviert.
ALTER TABLE dbo.ProjectMembers NOCHECK CONSTRAINT fk_ProjectMembers_Employee_Id;
Nach der Ausführung der Abfrage ergibt sich für die Ausführung ein vollständig neues Bild.
Microsoft SQL Server muss nun alle in die Abfrage involvierten Relationen prüfen. Zunächst wird eine Ergebnismenge der beiden Relationen [dbo].[Employees] und [dbo].[ProjectMembers] mittels eines – teuren – Hash Match gebildet; anschließend wird diese Ergebnismenge mit [dbo].[Projects] verbunden und das Ergebnis an den Client geschickt. Statt eines – effektiveren – Merge Join muss ein – teurer – Hash Join verwendet werden, da Schlüsselattribute innerhalb der Abfrage nicht sortiert vorliegen. Weitere Informationen zu den physikalischen Operatoren für JOINS kann man im Buch “SQL Server Execution Plans” von Grant Fritchey nachlesen. Die unterschiedlichen Ausführungspläne machen sich natürlich auch im I/O bemerkbar, das durch die Abfragen generiert werden.
I/O mit Fremdschlüssel
ProjectMembers-Tabelle. Scananzahl 1, logische Lesevorgänge 34, ...
Projects-Tabelle. Scananzahl 1, logische Lesevorgänge 2, ...
I/O ohne Fremdschlüssel
Worktable-Tabelle. Scananzahl 0, logische Lesevorgänge 0, ...
ProjectMembers-Tabelle. Scananzahl 1, logische Lesevorgänge 34, ...
Employees-Tabelle. Scananzahl 1, logische Lesevorgänge 4, ...
Projects-Tabelle. Scananzahl 1, logische Lesevorgänge 2, ...
Zusammenfassung
Microsoft SQL Server kann jede Art der “Unterstützung” gebrauchen, um optimale Ausführungspläne zu erstellen. Sicherlich ist die primäre Aufgabe einer Fremdschlüssel-Einschränkung nicht die Optimierung von Ausführungsplänen sondern die Durchsetzung von Datenintegrität; dennoch ist es bemerkenswert, dass Microsoft SQL Server basierend auf solchen Regeln Ausführungen von Abfragen vereinfachen und damit auch optimieren kann.
Herzlichen Dank fürs Lesen!
Print article | This entry was posted by Uwe Ricken on 06.12.13 at 11:31:00 . Follow any responses to this post through RSS 2.0. |