Files
it-know-how/datenbanken/Identity Columns.md
T
2026-03-27 12:58:01 +01:00

14 KiB
Executable File
Raw Blame History

#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:

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):

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:

CREATE TABLE kunde (
    kunde_id BIGINT GENERATED ALWAYS AS IDENTITY PRIMARY KEY,
    name TEXT NOT NULL,
    email TEXT NOT NULL
);

MySQL-Beispiel:

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:

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:

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:

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:

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:

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:

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:

    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:

    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)

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)

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