Deep Dive

Warum Faker bei Fremdschlüsseln zerbricht

Faker ist hervorragend in genau einer Sache: einen einzelnen realistischen Wert erfinden. Der Ärger fängt an, sobald deine Daten Beziehungen haben. Hier ist genau, wo es bei Masse auseinanderfliegt, mit Code, und wie referenziell konsistente Daten stattdessen aussehen.

SeedBase · ~6 Min. Lesezeit

Vorweg klar: Faker ist eine großartige Bibliothek. Wenn du einen plausiblen Namen, eine E-Mail, eine Adresse oder einen Zeitstempel brauchst, nimm sie. Das Problem sind nicht die Werte. Das Problem ist, dass Faker jeden Wert unabhängig erzeugt, und eine echte Datenbank ist das genaue Gegenteil von unabhängig.

Der Bruch, in einem Snippet

Angenommen, du fakest Nutzer, Bestellungen und Bestellpositionen in Python:

from faker import Faker
fake = Faker()

users  = [{"id": i, "name": fake.name(), "email": fake.email()} for i in range(1, 1001)]
orders = [{"id": i,
           "user_id": fake.random_int(min=1, max=1000),
           "total":   fake.pydecimal(left_digits=4, right_digits=2, positive=True)}
          for i in range(1, 5001)]
items  = [{"id": i,
           "order_id":   fake.random_int(min=1, max=5000),
           "product_id": fake.random_int(min=1, max=200),
           "quantity":   fake.random_int(min=1, max=5)}
          for i in range(1, 20001)]

Läuft durch, und die Zeilen sehen gut aus. Dann lädst du sie mit aktivierten Constraints in eine echte Datenbank:

ERROR:  insert or update on table "order_items" violates
        foreign key constraint "order_items_product_id_fkey"
DETAIL:  Key (product_id)=(173) is not present in table "products".

Es gibt hier gar keine products-Tabelle, product_id zeigt also ins Leere. Und das ist noch der gute Fall, in dem der Fehler offensichtlich ist.

Die vier Dinge, die bei Masse brechen

1. Fremdschlüssel zeigen auf Zeilen, die es nicht gibt

Der random_int(min=1, max=1000)-Trick funktioniert nur, wenn die Eltern-IDs exakt 1..1000 sind, ohne Lücken, vor den Kindern erzeugt, und du jeden Bereich für jede Beziehung von Hand begrenzt. Sobald deine Keys UUIDs sind, es Lücken gibt oder ein Eltern-Set gefiltert ist, ist der Trick weg. Faker hat kein Konzept von "einer ID, die bereits existiert".

2. Nichts ist in Insert-Reihenfolge

Ein echtes Laden muss users vor orders einfügen und orders vor order_items. Faker gibt dir drei unabhängige Listen. Entweder sortierst du den Abhängigkeitsgraph selbst topologisch, oder du deaktivierst die Constraints beim Laden, was bedeutet, dass du Daten ausspielst, die in Produktion nie existieren könnten.

3. Die Verteilung ist gleichförmig, Produktion ist es nie

Weil jede user_id gleichverteilt zufällig ist, bekommt jeder Nutzer ungefähr gleich viele Bestellungen. Echte Daten haben einen langen Schwanz: die meisten haben ein, zwei, ein paar haben Dutzende. Genau dieser Schwanz ist, wo Pagination, N+1-Queries und langsame Joins umkippen. Gleichförmige Fake-Daten verstecken genau die Bugs, die du finden willst.

4. Werte sind über Spalten hinweg inkohärent

Faker füllt jede Spalte für sich, die E-Mail passt also nicht zum Namen (fake.name() gibt "Alex Miller", fake.email() gibt "wsmith@example.org"), und order.total hat keinen Bezug zur Summe seiner Positionen. Jeder Test, der einen abgeleiteten oder denormalisierten Wert prüft, ist damit wertlos.

Bonus-Bruch: Eindeutigkeit. Bei Masse wiederholt sich fake.email() und reißt eine UNIQUE-Constraint. Wechselst du zu fake.unique.email(), erschöpft Faker irgendwann seinen Pool und wirft UniquenessException. So oder so schreibst du Retry-Logik um einen Datengenerator herum.

Was du eigentlich willst

Du willst Daten, die per Konstruktion referenziell konsistent sind: Kinder referenzieren nur existierende Eltern, Inserts kommen Eltern-zuerst, Verteilungen sind schief wie im echten Leben, und abgeleitete Werte sind rekonziliert. Das ist kein Faker-Aufruf, das ist eine Eigenschaft des ganzen Datensatzes, abgeleitet aus deinem Schema.

Genau diese Linie zieht SeedBase. Du gibst dein Schema rein (SQL, eine Django-models.py oder ein Prisma-Schema) und es:

Kein Faker-Ersatz, eine Schicht darüber. Faker ist eine gute Wert-Bibliothek, die Art Ding, das in einem Generator lebt. Was es nicht liefert, ist eine ladbare relationale Datenbank. SeedBase wurde an einem echten Django-Projekt mit 20 Apps und 226 Tabellen getestet, daher kommt die Fremdschlüssel- und Verteilungs-Behandlung. EU-gehostet, keine Drittanbieter-Tracker, alles exportierbar.

Die Kurzfassung

Faker macht großartige Werte und null Garantien darüber, wie sie zusammenpassen. Für eine einzelne Spalte ist das alles, was du brauchst. Für eine Datenbank mit Beziehungen sind "gültiger Wert pro Zelle" und "gültiger Datensatz" verschiedene Probleme, und nur das zweite lädt.

Daten, die wirklich laden

Zeig SeedBase dein Schema und generiere eine befüllte, FK-konsistente Datenbank mit realistischen Verteilungen. Free-Tier, keine Kreditkarte.

  • Jeder FK geht auf
  • Long-Tail-Verteilungen
  • SQL / CSV / JSON
  • EU-gehostet
FK-konsistente Daten generieren, kostenlos

Mehr: SeedBase vs Faker · Django-DB befüllen · Testdaten generieren