Ein einzelnes UPDATE oder DELETE über Millionen von Zeilen kann Datenbank-Locks minutenlang halten, Replikate ins Hintertreffen geraten lassen oder während Deployments in Timeouts laufen. Queue-SQL, ein Laravel-Paket von Kamran Atayev, löst das, indem es große Schreiboperationen auf parallele Queue-Jobs aufteilt: Es ermittelt Minimum und Maximum der Primärschlüssel einer Abfrage, zerlegt den ID-Bereich in begrenzte Scheiben und dispatcht ein Illuminate\Bus\Batch, das jede Scheibe unabhängig verarbeitet.
Das Paket registriert ein queue()-Macro auf Query Builder und Eloquent und stellt update, delete, insert und upsert bereit. Constraints werden in SQL-Fragmente und Bindings kompiliert, sodass verschachtelte Closures, whereHas, whereExists und Sub-Selects die Worker ohne Serialisierungsprobleme erreichen. Die Job-Größe wird über chunk (Zeilen pro Job) oder maxJobs (Ziel-Gesamtzahl über den Schlüsselbereich) gesteuert; beide zusammen werfen eine InvalidArgumentException. dispatch() gibt ein natives Illuminate\Bus\Batch mit then, catch, finally und allowFailures zurück.
In der Praxis hängt man queue() vor die Schreibmethode und beendet die Kette mit dispatch() — vorher wird nichts in die Queue gestellt. Beispiel: Order::where('status', 'complete')->queue(chunk: 25000, tries: 2, onQueue: 'maintenance', throttle: 4)->update(['status' => 'completed'])->dispatch(). Der throttle-Parameter begrenzt die Jobs pro Sekunde und schützt Datenbankverbindungen und Replikate bei großen Backfills. Deletes nutzen dieselbe Syntax; Bulk-Inserts verzichten auf Schlüsselbereichsplanung und teilen stattdessen das Datensatz-Array auf Jobs auf.
Da jeder Update- oder Delete-Job einen festen Schlüsselbereich bearbeitet, sind Retries idempotent. Wiederholte Insert-Jobs sind das nicht und können Duplikate erzeugen — die Doku empfiehlt einen Unique-Index oder upsert(), wenn Retry-Sicherheit nötig ist. Gegenüber Laravels Prunable-Trait und model:prune, die sequenziell in einem Prozess löschen, arbeitet Queue-SQL parallel, trackt den Fortschritt als Batch und beherrscht zusätzlich beliebige Updates und Bulk-Inserts.
Ersetzt man dispatch() durch dryRun(), erhält man eine Vorschau des Batching-Plans (Operation, Tabelle, Job-Anzahl, Bereiche, geschätzte Zeilen), ohne Jobs zu queuen. Die Schlüsselbereichs-Bildung basiert auf Min/Max der Primärschlüssel statt exakter Zeilenzahlen; bei Tabellen mit großen ID-Lücken verarbeiten einige Jobs weniger Zeilen, die Gesamtzahl der Jobs bleibt aber fix.
Die CLI überwacht Batches direkt über die Batch-Tabelle des Frameworks: queue-sql:status listet oder inspiziert Batches, queue-sql:cancel bricht einen ab, --watch aktualisiert in interaktiven Terminals alle zwei Sekunden (in nicht-interaktiven Umgebungen nur einmalig), --json formatiert die Ausgabe. Die Statusanzeige zeigt Gesamt-, offene und fehlgeschlagene Jobs, Fortschritt in Prozent und den Batch-Status. Horizon-Jobs werden automatisch mit queue-sql, Operationstyp und Zieltabelle getaggt. Globale Defaults für Chunk-Größe, Retries, Backoff, Throttling, Delays und Queue-Namen liegen in config/queue-sql.php.
Voraussetzungen sind PHP 8.1+ und Laravel 10 bis 13, unterstützt werden SQLite, MySQL und PostgreSQL. Installation per composer require kamranata/queue-sql, danach queue:batches-table und migrate, da das Paket auf nativen Job Batches aufbaut. Zwei Einschränkungen: Das Slicing benötigt einen auto-inkrementierenden Integer-Primärschlüssel (sonst läuft alles in einem einzelnen Job), und die Schlüsselgrenzen werden beim dispatch() fixiert — später eingefügte Zeilen mit höheren IDs werden nicht erfasst. Ein Benchmark-Skript (benchmarks/lock_duration.php) liegt dem Repo bei; in einem Test mit 20.000 gelöschten Zeilen unter SQLite hielt ein ungebündeltes DELETE den Lock 3,6-mal länger als der längste von Queue-SQL gemessene Lock.
Kommentare
Noch keine Kommentare — schreib den ersten.
Starte die Diskussion
Kein Konto, kein Passwort nötig — gib einfach deine E-Mail-Adresse ein, wir senden dir einen einmaligen Anmelde-Link. Beim ersten Mal bist du damit automatisch angemeldet.
Deine Bewertung wird nach der Anmeldung automatisch übernommen.
Schau in dein Postfach
Wir haben einen Anmelde-Link an … gesendet. Öffne ihn auf diesem Gerät — dieser Tab meldet dich automatisch an.
Warte auf deinen Klick …
·