add synced notes on IT know how

This commit is contained in:
Mathias Schneider
2026-03-17 19:01:50 +01:00
parent b8797d5ca8
commit fc3aef4da8
31 changed files with 13162 additions and 1 deletions
@@ -0,0 +1,497 @@
#datenbank
➡️ [[#Zusammenfassung]]
---
## 1. Grundidee: Was ist eine Identity Column?
Stell dir eine Tabelle „Kunden“ vor. Jeder Kunde soll eine eindeutige Nummer bekommen:
- Kunde 1
- Kunde 2
- Kunde 3
-
Du willst diese Nummern **nicht selbst vergeben**, sondern die Datenbank soll das **automatisch** machen, wenn du einen neuen Datensatz einfügst.
Genau das ist eine **Identity Column**:
> Eine Identity Column ist eine Spalte, deren Wert von der Datenbank automatisch erzeugt wird, meist als laufende Nummer (1, 2, 3, …). Sie wird oft als Primärschlüssel benutzt.
Typische Eigenschaften:
- numerisch (z.B. `INT`, `BIGINT`)
- beim `INSERT` wird kein Wert angegeben die DB füllt ihn selbst
- der Wert ist pro Tabelle eindeutig
- er steigt (meist) monoton an (1,2,3,…), kann aber Lücken haben
---
## 2. Ein einfaches Beispiel
Beispiel in **SQL Server**:
```sql
CREATE TABLE Kunde (
KundeID INT IDENTITY(1,1) PRIMARY KEY, -- Start bei 1, Inkrement 1
Name NVARCHAR(100) NOT NULL,
Email NVARCHAR(200) NOT NULL
);
-- Einfügen ohne KundeID anzugeben:
INSERT INTO Kunde (Name, Email)
VALUES ('Anna Beispiel', 'anna@example.com'),
('Max Muster', 'max@muster.de');
-- Auslesen:
SELECT * FROM Kunde;
```
Ergebnis (vereinfacht):
```text
KundeID | Name | Email
--------+----------------+-------------------
1 | Anna Beispiel | anna@example.com
2 | Max Muster | max@muster.de
```
Du hast `KundeID` nie selbst gesetzt die Datenbank hat sie erzeugt.
---
## 3. Abgrenzung zu verwandten Begriffen
### 3.1 Identity Column vs. Primärschlüssel
- **Primärschlüssel (Primary Key)**:
Konzept: eine oder mehrere Spalten, die **eindeutig** einen Datensatz identifizieren.
- **Identity Column**:
Mechanismus: eine Spalte, deren Werte automatisch generiert werden.
Eine Identity Column **kann** der Primärschlüssel sein, muss aber nicht. Man kann auch:
- Identity Column + separater fachlicher Schlüssel (z.B. Kundennummer im ERP)
- Primärschlüssel auf einer anderen Spalte (z.B. E-Mail) ohne Identity Column
In der Praxis: Sehr häufig ist die Identity Column = Primärschlüssel.
---
### 3.2 Identity Column vs. Auto-Increment
Viele Systeme benutzen unterschiedliche Begriffe:
- SQL Server: `IDENTITY`
- PostgreSQL: `GENERATED AS IDENTITY` (früher `SERIAL`)
- MySQL: `AUTO_INCREMENT`
- Oracle: Identity-Spalten oder separate `SEQUENCE`
**Inhaltlich** ist „Identity Column“ oft gleichbedeutend mit „Auto-Increment-Spalte“: eine automatisch hochzählende Spalte.
PostgreSQL-Beispiel:
```sql
CREATE TABLE kunde (
kunde_id BIGINT GENERATED ALWAYS AS IDENTITY PRIMARY KEY,
name TEXT NOT NULL,
email TEXT NOT NULL
);
```
MySQL-Beispiel:
```sql
CREATE TABLE kunde (
kunde_id BIGINT AUTO_INCREMENT PRIMARY KEY,
name VARCHAR(100) NOT NULL,
email VARCHAR(200) NOT NULL
);
```
---
### 3.3 Identity Column vs. Sequence
**Sequence (Sequenz)** ist ein **eigenständiges Datenbankobjekt**, das Zahlen generiert, etwa so:
```sql
CREATE SEQUENCE kunde_seq START WITH 1 INCREMENT BY 1;
SELECT nextval('kunde_seq'); -- gibt 1 zurück
SELECT nextval('kunde_seq'); -- gibt 2 zurück
```
Eine Identity Column ist oft intern an eine Sequence gekoppelt.
Unterschied:
- Sequence: unabhängig von Tabellen, du kannst sie überall verwenden
- Identity Column: an genau eine Spalte gebunden, automatischer Einsatz bei `INSERT`
In einigen DB-Systemen (z.B. Oracle, PostgreSQL) sind Identity Columns technisch eine bequeme Hülle um eine Sequence.
---
### 3.4 Identity Column vs. natürlicher/fachlicher Schlüssel
- **Natürlicher/fachlicher Schlüssel**: basiert auf echten Geschäfts-Daten
Beispiele:
- E-Mail-Adresse als eindeutiger Schlüssel für Benutzer
- ISBN für Bücher
- Personalnummer aus dem HR-System
- **Surrogate Key** (hier passt die Identity Column): technischer, künstlicher Schlüssel, ohne fachliche Bedeutung.
Identity Columns sind **Surrogate Keys**:
- `KundeID = 42` sagt fachlich nichts über den Kunden aus
- sie existiert nur, um Zeilen eindeutig zu identifizieren
In vielen Projekten arbeitet man mit:
- Identity Column als Primärschlüssel
- dazu Unique-Constraints auf fachlichen Spalten (z.B. `Email UNIQUE`)
---
### 3.5 Identity Column vs. UUID / GUID
Statt einer Identity Column (INT) kann man auch **UUIDs** (z.B. `UUID`, `uniqueidentifier`) als Primärschlüssel verwenden.
Unterschiede:
- **Identity (INT/BIGINT)**:
- kleiner, effizienter Index
- gut lesbar (`KundeID = 123`)
- nicht global eindeutig über mehrere Systeme, nur innerhalb der Tabelle
- lässt leicht Rückschlüsse auf Anzahl/Abfolge (z.B. „wir sind bei Kunde 10.000“)
- **UUID**:
- sehr große, „zufällig“ wirkende Zeichenfolge
- global eindeutig (sehr hoch wahrscheinlich)
- schwerer zu merken/lesen
- Indexe sind meist größer, Einfügen kann teurer sein
Z.B. in PostgreSQL:
```sql
CREATE TABLE kunde (
kunde_id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
name TEXT NOT NULL
);
```
Identity Column und UUID sind also alternative Strategien zur ID-Erzeugung.
---
## 4. Welche Probleme löst eine Identity Column?
### 4.1 Eindeutige Identifikation von Datensätzen
Jede Zeile bekommt automatisch eine eindeutige ID:
- kein Risiko, dass zwei Datensätze „versehentlich“ dieselbe ID haben
- Voraussetzung für saubere Joins, Fremdschlüssel, Referenzen
Beispiel: Fremdschlüssel von Auftrag auf Kunde:
```sql
CREATE TABLE Kunde (
KundeID INT IDENTITY(1,1) PRIMARY KEY,
Name NVARCHAR(100) NOT NULL
);
CREATE TABLE Auftrag (
AuftragID INT IDENTITY(1,1) PRIMARY KEY,
KundeID INT NOT NULL,
Betrag DECIMAL(10,2) NOT NULL,
FOREIGN KEY (KundeID) REFERENCES Kunde(KundeID)
);
```
Beim Anlegen eines Auftrags verweist `Auftrag.KundeID` auf `Kunde.KundeID`.
---
### 4.2 Vereinfachung beim Einfügen von Daten
Ohne Identity Column müsstest du bei jedem `INSERT` einen neuen eindeutigen Wert berechnen und eintragen in Mehrbenutzer-Umgebungen ist das fehleranfällig.
Mit Identity Column:
```sql
INSERT INTO Kunde (Name) VALUES ('Lisa Test'); -- ID macht die DB
```
Du musst dir keine Gedanken machen über:
- die nächste freie Nummer
- Race Conditions (zwei Nutzer generieren zufällig dieselbe ID)
- Sperren von Tabellen, etc.
---
### 4.3 Unterstützung von Mehrbenutzerbetrieb
In einer Datenbank arbeiten meist viele Nutzer oder Prozesse parallel. Identity Columns sind so implementiert, dass:
- gleichzeitig eingefügte Zeilen **ohne Kollision** IDs bekommen
- du dich nicht um Synchronisation kümmern musst
Die Datenbank regelt intern:
- Sperren der Sequenz
- Transaktionssicherheit
---
### 4.4 Gute Performance und einfache Indizierung
Numerische Identity-Spalten:
- sind kompakt (z.B. 4 oder 8 Byte)
- lassen sich effizient indexieren
- wachsen meist monoton -> B-Tree-Indizes funktionieren sehr performant
Im Vergleich:
- komplexe Primärschlüssel aus mehreren Textspalten sind größer, langsamer
- Identity-Spalte als „technischer Schlüssel“ macht viele Operationen schneller
---
## 5. Herausforderungen und typische Fallstricke
### 5.1 Lücken in der Nummernfolge
Anfänger erwarten oft: „Wenn ich einen Datensatz lösche oder eine Transaktion zurückrolle, füllt die DB die Nummer wieder auf.“
Das **passiert nicht** (und sollte auch nicht passieren).
Gründe für Lücken:
- Transaktion wird zurückgerollt nach dem Erzeugen einer ID
- Datensatz mit ID 10 wird gelöscht
- Parallel eingefügte Datensätze
Beispiel:
- du fügst einen Datensatz ein -> bekommt ID 10
- im gleichen Moment ein zweiter -> ID 11
- deine Transaktion schlägt fehl -> Datensatz 10 existiert nicht
- Datensatz 11 bleibt erhalten
Ergebnis: Es gibt jetzt mitunter keinen Datensatz mit ID 10. Das ist normal.
**Wichtige Praxisregel**:
Eine Identity Column ist eine **technische ID**, keine „lückenlose Rechnungsnummer“, keine „fortlaufende Kundennummer“ im rechtlichen Sinn.
Wenn du wirklich lückenlose Nummern brauchst (z.B. für Rechnungen), wird das typischerweise anders gelöst (spezialisierte Logik, Sperren, eigene Tabellen).
---
### 5.2 „ID = Reihenfolge“ ist gefährlich
Menschen neigen dazu zu denken:
> „ID 100 wurde nach ID 99 erstellt.“
In der Praxis ist das oft, aber **nicht garantiert**:
- Backups/Restores
- Replikation
- Imports aus anderen Systemen
- unterschiedliche Identity-Strategien
Besser: Wenn du die zeitliche Reihenfolge brauchst, verwende eine **Zeitstempel-Spalte**:
```sql
CREATE TABLE Kunde (
KundeID INT IDENTITY(1,1) PRIMARY KEY,
Name NVARCHAR(100),
CreatedAt DATETIME2 NOT NULL DEFAULT SYSDATETIME()
);
```
Dann sortierst du nach `CreatedAt`, nicht nach `KundeID`.
---
### 5.3 Limits des Datentyps (Überlauf)
Wenn du `INT` (32-Bit) verwendest, ist irgendwann Schluss (ca. 2,1 Milliarden positive Werte). Bei sehr großen Tabellen oder sehr intensiver Nutzung kann das relevant werden.
Praktischer Tipp:
- lieber direkt `BIGINT` für Identity-Spalten verwenden die Grenze ist so hoch, dass du in normalen Anwendungen nicht anstößt.
Beispiel:
```sql
CREATE TABLE Bestellung (
BestellungID BIGINT IDENTITY(1,1) PRIMARY KEY,
...
);
```
---
### 5.4 Datenmigrationen, Importe, Reseeding
Problemfälle:
- du willst Daten von einem System ins andere migrieren
- dort gibt es schon Datensätze mit Identity-Werten
- beim Import dürfen keine IDs kollidieren
Strategien:
1. **Identity-Werte mit übernehmen**
In vielen DB-Systemen kann man temporär eigene Werte setzen:
SQL Server:
```sql
SET IDENTITY_INSERT Kunde ON;
INSERT INTO Kunde (KundeID, Name, Email)
VALUES (1001, 'Imported User', 'import@example.com');
SET IDENTITY_INSERT Kunde OFF;
```
2. **Nach dem Import die Identity „neu starten“ (reseeden)**
SQL Server:
```sql
DBCC CHECKIDENT ('Kunde', RESEED, 2000); -- nächste ID = 2001
```
Diese Themen werden wichtig, wenn du Daten zwischen Systemen hin- und herschiebst.
---
### 5.5 Verteilte Systeme / Sharding
In modernen Architekturen gibt es manchmal:
- mehrere Datenbankserver (Shards)
- die später zusammengeführt werden sollen
Wenn jede Tabelle eine Identity-Spalte bei 1 beginnen lässt, kann es bei Merge-Vorgängen Kollisionen geben (z.B. `KundeID = 100` existiert auf zwei Servern mit unterschiedlichen Kunden).
Lösungen:
- pro Server unterschiedliche Startwerte und Inkremente:
- Server A: `IDENTITY(1, 3)` → 1,4,7,…
- Server B: `IDENTITY(2, 3)` → 2,5,8,…
- Server C: `IDENTITY(3, 3)` → 3,6,9,…
- oder Nutzung von UUIDs statt Identity-Spalten
---
### 5.6 Informationsleck (Datenschutz, Sicherheit)
Außen sichtbare IDs (z.B. in URLs) können Informationen verraten:
- wenn dein Kunde eine URL wie `/bestellung/1000` sieht, kann er ahnen, dass es ~1000 Bestellungen gibt
- er kann versuchen, `/bestellung/999` aufzurufen (ID-Raten)
Das ist kein Problem der Identity-Spalte an sich, sondern der Entscheidung, **diese ID außerhalb der Anwendung sichtbar** zu machen.
Lösungen:
- Zugriffskontrollen („zeige nur eigene Bestellungen“)
- andere, „nicht-erratbare“ IDs für externe Darstellung (z.B. UUIDs, Hashes)
---
### 5.7 Portabilität zwischen Datenbanksystemen
Jede Datenbank hat leicht andere Syntax:
- SQL Server: `INT IDENTITY(1,1)`
- PostgreSQL: `GENERATED ALWAYS AS IDENTITY`
- MySQL: `AUTO_INCREMENT`
- Oracle: `GENERATED BY DEFAULT AS IDENTITY` oder Sequences
Wenn du Wert auf **Portabilität** legst (dass dein Schema in mehreren DB-Systemen läuft), musst du darauf achten:
- eher Standard-SQL (`GENERATED [ALWAYS|BY DEFAULT] AS IDENTITY`)
- oder ID-Generierung in der Anwendung selbst
---
## 6. Praxisnahe Gesamtbeispiele
### 6.1 Einfache Kunden- und Bestellverwaltung (SQL Server-Variante)
```sql
CREATE TABLE Kunde (
KundeID INT IDENTITY(1,1) PRIMARY KEY,
Name NVARCHAR(100) NOT NULL,
Email NVARCHAR(200) NOT NULL UNIQUE,
CreatedAt DATETIME2 NOT NULL DEFAULT SYSDATETIME()
);
CREATE TABLE Bestellung (
BestellungID INT IDENTITY(1,1) PRIMARY KEY,
KundeID INT NOT NULL,
Datum DATETIME2 NOT NULL DEFAULT SYSDATETIME(),
Betrag DECIMAL(10, 2) NOT NULL,
FOREIGN KEY (KundeID) REFERENCES Kunde(KundeID)
);
-- Neuen Kunden anlegen:
INSERT INTO Kunde (Name, Email)
VALUES ('Anna Beispiel', 'anna@example.com');
-- Die ID des eben eingefügten Kunden holen:
SELECT SCOPE_IDENTITY() AS NeueKundeID;
```
`SCOPE_IDENTITY()` gibt dir in SQL Server die zuletzt erzeugte Identity in der aktuellen Session und dem aktuellen Scope. Damit kannst du *direkt danach* eine Bestellung für genau diesen Kunden anlegen.
---
### 6.2 Beispiel in PostgreSQL (moderner Standard)
```sql
CREATE TABLE kunde (
kunde_id BIGINT GENERATED ALWAYS AS IDENTITY PRIMARY KEY,
name TEXT NOT NULL,
email TEXT NOT NULL UNIQUE,
created_at TIMESTAMPTZ NOT NULL DEFAULT now()
);
CREATE TABLE bestellung (
bestellung_id BIGINT GENERATED ALWAYS AS IDENTITY PRIMARY KEY,
kunde_id BIGINT NOT NULL REFERENCES kunde(kunde_id),
datum TIMESTAMPTZ NOT NULL DEFAULT now(),
betrag NUMERIC(10,2) NOT NULL
);
-- Einfügen:
INSERT INTO kunde (name, email)
VALUES ('Max Muster', 'max@muster.de')
RETURNING kunde_id; -- PostgreSQL-spezifisch, um die ID direkt zu bekommen
```
---
## Zusammenfassung
- Eine **Identity Column** ist eine Spalte, deren Wert die Datenbank automatisch erzeugt (typisch: laufende Nummer).
- Sie wird häufig als **Primärschlüssel** verwendet, ist aber **nicht dasselbe** wie der Begriff „Primärschlüssel“.
- Sie löst v.a. diese Probleme:
- eindeutige Identifikation von Zeilen
- einfache Inserts, ohne selbst IDs zu erzeugen
- sichere Nutzung in Mehrbenutzer-Umgebungen
- gute Performance bei Indexen und Joins
- Sie ist verwandt mit:
- Auto-Increment-Spalten (`AUTO_INCREMENT`, `SERIAL`)
- Sequences (`SEQUENCE`)
- Surrogate Keys im Gegensatz zu natürlichen Schlüsseln
- Alternativen wie UUID/GUID
- Typische Herausforderungen:
- Lücken in der Nummernfolge (normal und erwünscht)
- ID ist nicht zuverlässig die zeitliche Reihenfolge
- Datenmigration, Reseeding, Sharding
- potenzielles Informationsleck, wenn IDs öffentlich sichtbar sind
- Unterschiede in der Implementierung zwischen Datenbanksystemen