Kaputte Suche und Filter in AI-CRUD-Apps: wie man sie repariert
Kaputte Suche und Filter machen AI-CRUD-Apps unbrauchbar. Lernen Sie, Query-Builder zu korrigieren, Filter einzuschränken, Injection zu verhindern und Abfragen mit Indexen zu beschleunigen.

Wie sich „kaputte Suche" in einer CRUD-App zeigt
Kaputte Suche fühlt sich an, als würde die App lügen. Sie tippen einen Namen ein, von dem Sie wissen, dass er existiert, und er erscheint nicht. Oder Sie filtern nach Status und bekommen plötzlich Datensätze, die eindeutig nicht passen.
Die häufigsten Symptome sind einfach zu erkennen:
- Fehlende Ergebnisse
- Doppelte Zeilen
- Eine Sortierung, die willkürlich wirkt
Duplikate entstehen oft durch Joins. Ein Datensatz wird zu vielen Zeilen, weil die Abfrage eine andere Tabelle join't und nie gruppiert oder dedupliziert. „Zufällige" Sortierung passiert normalerweise, wenn keine stabile Sortierung vorhanden ist, sodass die Datenbank Zeilen in der Reihenfolge zurückgibt, die gerade am bequemsten ist.
Diese Probleme werden schlimmer, je mehr Daten da sind. Bei 50 Datensätzen fällt ein gelegentlich ignorierter Filter vielleicht nicht auf. Bei 50.000 Datensätzen wird derselbe Bug zu Timeouts, halb geladenen Seiten und Nutzern, die aufgeben, weil sie nichts finden.
Wenn die Suche einmal unzuverlässig wirkt, hören Menschen auf, der gesamten App zu vertrauen. Sie nehmen an, dass die Daten falsch sind, nicht die Abfrage. Support-Tickets steigen, und Teams führen eigene Tabellen, weil das System of record sich nicht mehr sicher anfühlt.
Eine schnelle Reproduktion des Problems: legen Sie ein paar leicht unterscheidbare Datensätze an. Zum Beispiel: eine Kundin namens "Ann Lee" (active), eine namens "Anne Li" (inactive) und einer namens "Bob" (active). Prüfen Sie dann:
- Suche "Ann" und bestätigen Sie, welche Datensätze erscheinen
- Filter status = active und bestätigen Sie, dass "Anne Li" verschwindet
- Zwei Mal nach Erstellungsdatum sortieren und bestätigen, dass die Reihenfolge gleich bleibt
Wenn ein Ergebnis Sie überrascht, ist die Suche kaputt — auch wenn sie nur „manchmal" versagt.
Warum AI-CRUD-Apps oft Suche und Filter falsch machen
Die meisten AI-CRUD-Apps starten als schnelle Demos. Suche und Filter werden spät dazugestellt und werden dann heimlich der Teil, den Nutzer auf jeder Seite berühren. Deshalb sind kaputte Suche und Filter so verbreitet: Sie werden unter Zeitdruck gebaut, mit kopiertem Code, der bis zu realen Daten und echten Nutzern gut aussieht — bis es das nicht mehr tut.
Eine häufige Ursache ist ein AI-generierter Query-Builder, der sichere Parametrisierung mit String-Konkatenation mischt. Er bindet Werte vielleicht an einer Stelle sicher, injiziert dann aber direkt eine Sortier-Spalte, einen Operator oder ein rohes WHERE-Fragment an einer anderen Stelle. Das erzeugt verwirrende Bugs (falsche Ergebnisse, fehlende Zeilen) und echtes Risiko (SQL-Injection durch „clevere" Filtereingaben).
Ein weiteres Problem ist, der UI alles zu erlauben: jeder Feldname, jeder Operator, jeder Wert. Das wirkt flexibel, aber das Backend rät dann oft nur die Absicht. Ein Nutzer sucht status, ein anderer nutzt createdAt, und wieder ein anderer versucht contains auf einer numerischen Spalte. Selbst wenn nichts abstürzt, wird das Verhalten inkonsistent und schwer zu testen.
Joins verschlechtern die Lage. Über mehrere verbundene Tabellen hinweg zu suchen ohne Plan führt zu Duplikaten, fehlenden Treffern und langsamen Abfragen. Eine „Customers"-Seite könnte Orders und Notes joinen und den Suchbegriff auf beide anwenden. Ohne klare Regeln für Gruppierung und Deduping kann ein Kunde mit vielen Orders mehrfach erscheinen und die Paginierung unzuverlässig werden.
Die Performance leidet oft aus demselben Grund: die Datenbank ist nicht für das indexiert, was Nutzer tatsächlich tun. Teams indexieren id und halten es für erledigt, während Produktionsqueries nach tenant_id + status filtern, nach created_at sortieren und nach E-Mail suchen.
Sicherheit zuerst: unsichere dynamische Filter stoppen
Kaputte Suche und Filter beginnen oft mit einer „flexiblen" Filterbox: Nutzer können jedes Feld, jeden Operator und jeden Wert senden. Wenn Ihre App diese Teile in einen SQL-String näht, kann ein Angreifer zusätzliche SQL-Anweisungen in die Abfrage schmuggeln. Einfach gesagt: sie filtern nicht nur Zeilen, sie verändern, was die Datenbank ausführt.
Ein gängiges Beispiel ist ein Filter wie status=active, der zu WHERE status = 'active' wird. Wenn jemand active' OR 1=1 -- sendet, kann die Abfrage „alles zurückgeben“. In schlimmeren Fällen können injizierte Texte sensible Tabellen lesen oder Daten verändern, je nach Rechten.
Escaping ist nicht dasselbe wie Parametrisierung. Escaping versucht, gefährliche Zeichen innerhalb eines Strings sicher zu machen. Parametrisierung (Prepared Statements) hält die SQL-Struktur fest und sendet Werte separat, sodass die Datenbank sie als Daten und nicht als Anweisungen behandelt.
Knifflig ist, dass viele Probleme bei „dynamischen Filtern" nicht die Werte betreffen. Besonders riskant sind Inputs, die die meisten SQL-Bibliotheken nicht parametrisierbar machen:
- Feldnamen (z. B.
sortBy=price) - Sortierrichtung (
asc/desc) - Operatoren (
=,LIKE,>,IN) - Rohe SQL-Snippets (
where=...,order=...) - Tabellen- oder Relationsnamen
Für diese Dinge: nicht einfach escapen und hoffen. Verwenden Sie Allowlists: definieren Sie exakt, welche Felder gefiltert oder sortiert werden dürfen, welche Operatoren pro Feld erlaubt sind und wie jede Option sicher auf SQL abgebildet wird.
Begrenzen Sie außerdem den Schaden mit Least-Privilege-Datenbankrollen. Selbst wenn eine schlechte Abfrage durchrutscht, sollte das Konto, das Ihre App nutzt, nicht in der Lage sein, Tabellen zu droppen oder admin-only Daten zu lesen.
Erstellen Sie einen klaren Filtervertrag (was erlaubt ist und was nicht)
Die meisten kaputten Filter entstehen, weil die App „irgendetwas" von der UI annimmt und versucht, es in eine Datenbankabfrage zu verwandeln. Ein Filtervertrag behebt das, indem er einfache Regeln setzt, welche Filter existieren, was sie bedeuten und wie ungültige Eingaben behandelt werden.
Halten Sie den Vertrag klein. Beginnen Sie mit einer kurzen Whitelist von filterbaren Feldern und den Operatoren, die Sie für jedes unterstützen. Zum Beispiel: status darf equals sein, aber nicht contains. Ein createdAt-Datum kann before und after sein, nicht Freitext.
Validieren Sie Typen, bevor Sie die Abfrage bauen. Behandeln Sie jedes Filter als typisiertes Input, nicht als String zum Einfügen in SQL: Strings mit Maximallänge, Zahlen mit Bereichsgrenzen, strikte Datumsformate, Enums, die erlaubte Werte haben müssen, Booleans nur true/false.
Fügen Sie Beschränkungen hinzu, damit eine Anfrage Ihre Datenbank nicht überlastet: maximale Seitengröße, maximale Anzahl Filter pro Request und maximale Suchtextlänge.
Legen Sie schließlich konsistente Regeln für leere, null- und unbekannte Werte fest. Wenn ein Filterwert leer ist, ignorieren Sie ihn oder lehnen Sie die Anfrage ab? Wenn ein Feldname unbekannt ist, geben Sie einen klaren Validierungsfehler? Diese Entscheidungen verhindern "Warum sind meine Ergebnisse verschwunden?"-Bugs.
Schritt-für-Schritt: einen Query-Builder refaktorisieren, der falsche Ergebnisse liefert
Kaputte Suche und Filter beginnen oft mit einem Query-Builder, der „flexibel" sein will und SQL-Strings zusammenklebt. Für eine Demo funktioniert das, später liefert es seltsame Ergebnisse, scheitert bei Anführungszeichen oder wird ein Sicherheitsrisiko.
Ein praktischer Refactor-Pfad
Schreiben Sie zuerst auf, was die UI wirklich braucht, in klarer Sprache. Zum Beispiel: „Kunden nach Name oder E-Mail suchen", „nach Status filtern", „nach Neueste sortieren", „25 pro Seite anzeigen". Wenn Sie das nicht klar beschreiben können, bleibt der Code unübersichtlich.
Refaktorieren Sie dann in kleinen Schritten:
- Sperren Sie erlaubte Inputs: welche Filter es gibt, welche Sortieroptionen existieren und auf welche Spalten sie gemappt werden.
- Bauen Sie WHERE nur mit Parametern (keine String-Konkatenation für Werte).
- Behandeln Sie Filter-Keys als untrusted: mappen Sie UI-Keys wie
statuszu bekannten Spalten wiecustomers.statusund lehnen Sie unbekannte Keys ab oder ignorieren Sie sie. - Machen Sie Sortierung stabil: fügen Sie einen Tie-Breaker hinzu (z. B.
created_atdannid), sodass Paginierung nicht überspringt oder wiederholt. - Legen Sie Paginierungsregeln explizit fest: mit
limitundoffsetstarten oder später Cursor-Paging verwenden, aber mischen Sie die Stile nicht.
Wenn die UI sort=createdAt sendet, übergeben Sie das nicht direkt an SQL. Übersetzen Sie es in einen festen, sicheren Snippet wie ORDER BY customers.created_at DESC, customers.id DESC.
Tests, die die "es sah gut aus"-Bugs auffangen
Einige gezielte Tests verhindern Regressionen:
- Namen mit Apostrophen (O'Connor)
- Emojis und nicht-lateinische Namen
- Gemischte Groß-/Kleinschreibung (alex vs Alex)
- Leere Suche mit angewendeten Filtern
- Unbekannte Filter-Keys (konsistent ignoriert oder abgelehnt)
Das richtige Suchverhalten wählen (und vorhersehbar halten)
Viel kaputte Suche ist eigentlich fehlende Regelklarheit. Wenn Nutzer nicht wissen, was das Suchfeld bedeutet, wirkt jedes Ergebnis falsch, selbst wenn die SQL genau das tut, was Sie gesagt haben.
Wählen Sie einen Standardmodus für die Suche und halten Sie ihn in der gesamten App bei. Gemischte Modi — exakte Übereinstimmung auf einem Screen und „contains" auf einem anderen — verwirren Nutzer schnell.
Exakte Übereinstimmung ist gut für IDs und E-Mails. Prefix-Match passt für Namen und Codes und kann mit dem richtigen Index schnell sein. Contains ist hilfreich, aber leicht auf großen Tabellen langsam. Fuzzy-Matching ist nützlich, wenn Tippfehler erwartet werden, aber das muss transparent gemacht werden.
Wenn Sie Contains-Suche nutzen, seien Sie vorsichtig mit Mustern wie LIKE '%term%' auf großen Tabellen. Das führende Wildcard erzwingt oft einen Full-Table-Scan.
Was immer Sie wählen: normalisieren Sie Eingaben überall gleich — trimmen Sie Leerzeichen, ignorieren Sie Groß-/Kleinschreibung, wenn das keinen Bedeutungsunterschied macht, und entscheiden Sie, wie Interpunktion behandelt wird. " Acme, Inc " sollte sich wie "acme inc" verhalten, aber "C++" darf nicht stillschweigend zu "c" werden.
Machen Sie es schnell: die richtigen Indexe für Ihre echten Queries
Wenn Nutzer sagen, die Suche sei langsam, beginnen Sie damit, die wenigen Queries zu finden, die am meisten weh tun. Raten führt zu zufälligen Index-Änderungen und neuen Bugs.
Indexe wirken am besten, wenn sie reale Muster abbilden: die Spalten in Ihrer WHERE-Klausel plus wie Sie sortieren. Wenn Ihre UI nach Status und Datum filtert und nach Neueste sortiert, hilft ein reiner Status-Index wenig.
Vermeiden Sie es, alles „nur für den Fall" zu indexieren. Jeder Index kostet: langsamere Writes, aufwändigere Migrationsschritte und mehr Pflegeaufwand. Fügen Sie eine kleine Anzahl gezielter Indexe hinzu und prüfen Sie die Performance mit realistischer Datenmenge erneut.
Paginierung und Sortierung, die unter Last nicht brechen
Paginierungsbugs zeigen sich als „Seite 2 wiederholt Einträge von Seite 1" oder „einige Zeilen verschwinden". Die Ursache ist meist instabile Sortierung. Wenn Sie nur nach created_at sortieren, teilen sich viele Zeilen denselben Timestamp, sodass die DB gebundene Reihen in beliebiger Reihenfolge zurückgeben kann. Wenn neue Zeilen zwischen Requests eingefügt werden, verschiebt sich die Reihenfolge und Items werden übersprungen oder wiederholt.
Verwenden Sie eine stabile Sortierung mit einem Tie-Breaker, z. B. ORDER BY created_at DESC, id DESC. Die id macht jede Zeile eindeutig, so bleibt „nächste Seite" vorhersagbar.
Offset-Paginierung (LIMIT 50 OFFSET 5000) ist simpel, wird aber langsamer mit wachsendem Offset. Für große Tabellen ist Cursor-/Keyset-Paginierung oft die bessere Wahl: statt „Seite 101" fragen Sie nach „den nächsten 50 Reihen nach diesem letzten gesehenen (created_at, id)".
Totale Counts können heimlich Ihre langsamste Abfrage werden. Ein gefiltertes COUNT(*) über eine große Tabelle kann viel Arbeit bedeuten, und das bei jeder Anfrage. Alternativen sind Counts nur bei Bedarf anzeigen, häufige Counts cachen oder hasNextPage mit LIMIT pageSize + 1 statt eines vollständigen Counts zurückgeben.
Schnell debuggen: langsame Suche und Filter
Wenn kaputte Suche als „es funktioniert, aber langsam" auftritt, behandeln Sie es zuerst als Messproblem. Raten führt zu zufälligen Index-Änderungen und neuen Fehlern.
Beginnen Sie damit, das tatsächliche SQL für nur die langsamen Requests zu erfassen. Beschränken Sie es auf eine Request-ID oder ein kurzes Zeitfenster und vermeiden Sie das Protokollieren roher Nutzereingaben, wenn diese E-Mails, Tokens oder andere sensible Daten enthalten könnten. Das Shape der Filter (welche Felder verwendet wurden) ist oft ausreichend.
Führen Sie dann EXPLAIN (oder das Äquivalent Ihrer DB) auf der genau ausgeführten SQL aus. Sie wollen wissen, ob die DB einen Index benutzt oder eine ganze Tabelle scannt und große Resultsets sortiert.
Häufige Performance-Killer:
- N+1-Queries (eine Abfrage für Zeilen, dann je eine pro Zeile für verwandte Daten)
- Unbegrenzte Joins (Joins großer Tabellen ohne selektiven Filter)
- Fehlende LIMIT (oder Paginierung, die trotzdem die ganze Tabelle sortiert)
- Filter, die Indexnutzung blockieren (Funktionen auf Spalten, führende Wildcards wie
%term) - Sortierung nach nicht-indexierter Spalte
Wenn Sie die Verlangsamung lokal nicht reproduzieren können, bauen Sie ein minimales Dataset, das das Verhalten zeigt. Verschwindet die Verlangsamung, ist das Problem oft Datenverteilung, nicht nur Code.
Häufige Fehler, die Sie beim Beheben vermeiden sollten
Escaping von Nutzerinput ist gut, aber es macht nicht automatisch die ganze Abfrage sicher. Ein sehr häufiger Bug in AI-CRUD-Apps ist es, Werte zu escapen, während der Client weiterhin rohe Spaltennamen senden kann wie ?sort=users.email oder ?filter[field]=status. Wenn jemand Spaltennamen, Operatoren oder SQL-Fragmente kontrollieren kann, kann er trotzdem die Abfrage brechen.
Dem Client jede Sortier-Spalte wählen zu lassen ist eine weitere Falle. Das verursacht Fehler (Sortieren nach einer Spalte, die Sie nicht selektiert haben), Datenlecks (Sortieren nach einem internen Feld) und Performance-Probleme (Sortieren nach einer nicht-indexierten Spalte auf einer großen Tabelle). Beschränken Sie Sortierung auf eine kleine Allowlist, die Sie wirklich unterstützen.
Filtern auf berechneten Feldern ist ebenfalls problematisch. Filtern nach full_name, wenn es aus first_name + last_name zusammengesetzt wird, oder „Tage seit letztem Login", das im Code berechnet wird, wird oft langsam oder inkonsistent. Wenn Sie darauf filtern müssen, überlegen Sie, das Feld zu persistieren, zu indexieren oder zu cachen.
Passen Sie nicht die Ergebnisse an, um Geschwindigkeit zu gewinnen (oder machen Sie es nicht langsam, um Ergebnisse zu korrigieren). Ein Wechsel von LEFT JOIN zu INNER JOIN kann zwar schneller werden, aber stillschweigend Datensätze entfernen. DISTINCT zu verwenden, um Duplikate zu verbergen, kann ein Join-Problem kaschieren und Paginierung und Counts verwirrend machen.
Checkliste kurz vor dem Deploy
Testen Sie die langweiligen Fälle. Die meisten Bugs verbergen sich in Randinputs, unerwarteten Kombinationen und Performance bei realen Daten.
Korrektheits-Checks: Anführungszeichen, Prozentzeichen, Unterstriche, Emojis, sehr lange Texte, mehrere Leerzeichen und leere Suche kombiniert mit Filtern. Ein gutes Ergebnis ist vorhersehbar, selbst wenn der Input unordentlich ist.
Sicherheits-Checks: Das Backend akzeptiert nur eine kleine Menge an Feldern und Operatoren, und jeder Wert wird als Parameter übergeben (Placeholders), niemals direkt in SQL eingefügt.
Performance-Checks: Messen Sie langsame Queries vor und nach Ihren Änderungen mit denselben Daten und Inputs. Dokumentieren Sie die Indexe, auf die Sie sich verlassen, damit zukünftige Änderungen die Arbeit nicht wieder aufheben.
Stabilitäts-Checks: Sortierung ist deterministisch (mit Tie-Breaker wie id) und Paginierung überspringt oder wiederholt keine Items, wenn neue Zeilen hinzukommen.
Beispiel: Eine kaputte "Customers"-Suche in einer AI-CRUD-App reparieren
Ein typischer Fall auf einer "Customers"-Seite: Filter nach Status (active, paused), Plan (Free, Pro), einem Signup-Datum-Bereich und einer schnellen Namenssuche.
Die Symptome wirken zufällig. „Active + Pro" gibt Kunden zurück, die nicht Pro sind, Namenssuche verpasst offensichtliche Treffer, und die Listenreihenfolge ändert sich bei jedem Refresh. Unter Last wird die Seite so langsam, dass sie timeouts.
Was normalerweise schief lief:
- Ein Join zu Plans oder Subscriptions multipliziert Zeilen, sodass ein Kunde mehrfach erscheint und Zählungen falsch werden.
- Sortierung wird aus rohem Input gebaut (unsicher und instabil).
- Die Datenbank scannt zu viel, weil kein Index das reale Filter- + Sort-Muster abdeckt.
Eine saubere Lösung beginnt damit, Filter langweilig und strikt zu machen: nur bekannte Felder zulassen, Typen validieren und Queries aus einem kleinen Vertrag bauen (status ist einer von X, plan ist einer von Y, Daten sind echte Datumswerte, name ist ein einfacher String).
Dann machen Sie Ergebnisse vorhersehbar: Filter zuerst anwenden, Sortier-Keys durch eine Allowlist übersetzen und einen stabilen Tie-Breaker (created_at dann id) hinzufügen, damit Paginierung nicht umsortiert.
Zum Schluss fügen Sie gezielte Indexe hinzu, die dem tatsächlichen Suchverhalten entsprechen. Für diesen Screen bedeutet das oft einen zusammengesetzten Index, der das häufigste Filter- + Sort-Kombinationsmuster abdeckt, plus eine separate Lösung für Namenssuche.
Wenn Sie eine AI-generierte Codebasis geerbt haben (Lovable, Bolt, v0, Cursor, Replit) mit verworrenen Query-Buildern und unsicheren dynamischen Filtern, kann FixMyMess (fixmymess.ai) mit einem kostenlosen Code-Audit beginnen, um die falschen Joins, riskante SQL-Stellen und die spezifischen Queries zu finden, die zuerst refaktoriert werden sollten. Viele Projekte lassen sich reparieren und innerhalb von 48–72 Stunden deployment-ready vorbereiten, sobald der Filtervertrag festgelegt ist.
Häufige Fragen
Wie erkenne ich, ob die Suche meiner App wirklich kaputt ist oder nur "eigenartig"?
Prüfen Sie drei Dinge: fehlende erwartete Treffer, doppelte Zeilen und inkonsistente Sortierung. Erstellen Sie ein kleines Set offensichtlicher Datensätze (ähnliche Namen, unterschiedliche Status) und wiederholen Sie dieselben Such-, Filter- und Sortieraktionen. Wenn Ergebnisse sich ändern oder überraschen, ist die Suche kaputt, auch wenn der Fehler nur "manchmal" auftritt.
Warum sehe ich doppelte Zeilen, nachdem ich Suche über verwandte Tabellen hinzugefügt habe?
Joins multiplizieren häufig Zeilen. Ein übergeordneter Datensatz (z. B. ein Kunde) kann viele verbundene Zeilen (z. B. Bestellungen) haben, und die Abfrage liefert eine Zeile pro Join-Treffer, sofern Sie nicht richtig gruppieren oder deduplizieren. Das kann auch die Paginierung brechen, weil die DB nach Zeilen und nicht nach eindeutigen Kunden paginiert.
Warum wirkt die Sortierung zufällig, obwohl ich nach Datum sortiere?
Meistens fehlt eine stabile Sortierung. Wenn Sie nur nach einer nicht-eindeutigen Spalte sortieren (z. B. created_at), haben viele Zeilen denselben Wert und die Datenbank kann gebundene Zeilen in beliebiger Reihenfolge zurückgeben. Fügen Sie einen Tie-Breaker hinzu, zum Beispiel created_at plus id, damit Ergebnisse über Refreshes und Seiten hinweg deterministisch bleiben.
Warum ist es eine schlechte Idee, der UI zu erlauben, beliebige Filterfelder oder Operatoren zu senden?
Flexibilität ist riskant. Wenn das Backend dem Client erlaubt, beliebige Feldnamen, Operatoren oder rohe SQL-Fragmente zu senden, erhalten Sie inkonsistentes Verhalten und ein echtes Injektionsrisiko. Sicherer ist eine Allowlist: definieren Sie genau, welche Felder gefiltert/gesortet werden dürfen, und übersetzen Sie UI-Keys in bekannte SQL-Spalten.
Was ist der sicherste Weg, dynamische Filter ohne SQL-Injection zu bauen?
Parameterisieren Sie Werte überall, wo es geht, und fügen Sie niemals Rohnutzerinput direkt in SQL-Strings ein. Für Teile, die sich nicht parameterisieren lassen (wie Sort-Spalte, Richtung oder Operator), verwenden Sie Allowlists und mappen jede erlaubte Option auf einen festen, sicheren SQL-Snippet. Escaping allein ersetzt keine Parameterisierung.
Was ist ein „Filtervertrag" und was sollte er enthalten?
Ein Filtervertrag ist klein und explizit. Wählen Sie eine kurze Liste unterstützter Filter, definieren Sie, welche Operatoren jedes Filter erlaubt, validieren Sie Typen (Enums, Datumswerte, Zahlen, Booleans) und legen Sie konsistentes Verhalten für leere oder unbekannte Eingaben fest. Ein strikter Vertrag verhindert "manchmal funktioniert es"-Bugs und macht Tests einfach.
Wie debugge ich langsame Suche und Filter, ohne zu raten?
Protokollieren oder erfassen Sie das exakte SQL für langsame Requests (ohne sensible Rohdaten zu dumpen), und führen Sie dann das Explain-Tool Ihrer Datenbank auf dieser Abfrage aus. Achten Sie auf Full-Table-Scans, große Sorts, ungebundene Joins und Muster, die Indexnutzung verhindern (z. B. führende Wildcards). Beheben Sie die schlimmste Abfrage zuerst, anstatt zufällig Indexe hinzuzufügen.
Welche Indexe helfen bei CRUD-Suchscreens am meisten?
Indexieren Sie die Spalten, die Sie tatsächlich filtern und sortieren — zusammen. Wenn Queries in Produktion nach tenant_id und status filtern und nach created_at sortieren, hilft oft ein zusammengesetzter Index, der dieses Muster abdeckt. Indexieren Sie nicht alles; fügen Sie einige gezielte Indexe hinzu und testen Sie mit realistischen Daten neu.
Warum wiederholt Paginierung Einträge oder überspringt Datensätze unter Last?
Offset-Paginierung wird langsamer, je größer der Offset, und instabile Sortierung verursacht Duplikate oder übersprungene Einträge zwischen Seiten. Verwenden Sie eine stabile Sortierung mit Tie-Breaker und ziehen Sie für große Tabellen Cursor-/Keyset-Paginierung in Betracht. Seien Sie außerdem vorsichtig mit COUNT(*) bei jedem Request; das kann schnell zur langsamsten Abfrage werden.
Woran erkenne ich, ob meine KI-generierte CRUD-App professionelle Hilfe braucht, um die Suche zu reparieren?
Wenn das Projekt von Generatoren wie Lovable, Bolt, v0, Cursor oder Replit stammt, achten Sie auf string-konkateniertes SQL, client-gesteuerte Sort-Keys, inkonsistente Suchregeln zwischen Bildschirmen und Joins, die Duplikate erzeugen. Wenn Sie eine schnelle Lösung wollen, kann FixMyMess mit einem kostenlosen Code-Audit starten, unsafe Filters erkennen und die spezifischen Queries zum Refactor aufzeigen — viele Projekte sind innerhalb von 48–72 Stunden repariert und deployment-ready.