technik: Volltext-Indizes von press_releases in eine eigene Suchtabelle auslagern
Ein FULLTEXT-Index zwingt MySQL bei JEDEM ADD COLUMN auf ALGORITHM=COPY. Auf press_releases (>1 GB) bedeutet das einen vollständigen Rebuild, während dessen kein Schreibzugriff möglich ist — im August hat genau das die Seite zum Stehen gebracht, weil die wartenden Requests PHP-FPM-Worker und DB-Verbindungen belegten. Die durchsuchbaren Felder liegen jetzt gespiegelt in `press_release_search`, die die Indizes trägt. Ihr Schema ist per Konstruktion stabil und wird nie erweitert; neue Felder gehören nach press_releases, wo sie ohne Volltext-Index Millisekunden kosten. Synchron hält sie ein Observer (alle Schreibzugriffe laufen über Eloquent, auch der Importer), reparieren lässt sie sich mit press-releases:reindex-search. Der Umstieg ist über mehrere Migrationen geteilt und schaltet erst um, wenn press_releases seine Indizes verloren hat — bis dahin sucht die Anwendung unverändert weiter. Die Drop-Migration verweigert den Dienst, solange der Suchindex unvollständig ist, und verwirft die gecachte Umschalt-Prüfung: Stünde dort noch der alte Stand, setzte der Rückfallpfad sein MATCH() auf einen soeben entfernten Index ab (MySQL-Fehler 1191) und jede Suche endete im 500er. Dazu die betriebliche Absicherung: - DB_LOCK_WAIT_TIMEOUT (Default 10 s) statt MySQLs einem Jahr. Requests scheitern bei einer laufenden Schemaänderung nach Sekunden, statt sich aufzustauen, bis keine Verbindung mehr frei ist. - Sessions und Cache nach Redis, damit eine blockierte MySQL-Tabelle nicht die gesamte Anwendung mitreißt. - db:online-alter als Notausgang (pt-online-schema-change), falls eine der kleinen FULLTEXT-Tabellen doch einmal groß wird. Percona-Toolkit ist bewusst nicht Teil des Standard-Setups. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
e6eca9c85f
commit
8fc18c239b
14 changed files with 1076 additions and 5 deletions
|
|
@ -536,10 +536,14 @@ class PressRelease extends Model
|
|||
return $query->where(function (Builder $outer) use ($tokens, $useFullText, $companyIds, $categoryIds): void {
|
||||
$outer->where(function (Builder $content) use ($tokens, $useFullText): void {
|
||||
if ($useFullText) {
|
||||
$content->whereFullText(
|
||||
// Der Volltext-Index liegt auf der Suchtabelle, nicht auf
|
||||
// press_releases — sonst wäre dort jedes ADD COLUMN ein
|
||||
// stundenlanger Rebuild (siehe PressReleaseSearchIndex).
|
||||
PressReleaseSearchIndex::constrain(
|
||||
$content,
|
||||
['title', 'subtitle', 'text', 'keywords'],
|
||||
$tokens->map(fn (string $token): string => '+'.$token.'*')->implode(' '),
|
||||
['mode' => 'boolean']
|
||||
['mode' => 'boolean'],
|
||||
);
|
||||
|
||||
return;
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue