db: Index auf companies.email

companies trug bisher nur (portal, slug), (portal, is_active), (created_at, id)
und einen FULLTEXT über (name, email, slug). Ein FULLTEXT-Index beantwortet
aber kein WHERE email = ? — jede Suche über die Firmen-E-Mail war ein voller
Tabellendurchlauf.

Gebraucht wird der Index für die Newsroom-Konsolidierung: Die schlüsselt
ausdrücklich über die Firmen-E-Mail, nicht über die Pressekontaktadresse, und
die laufende Zuordnung neuer API-Meldungen führt diesen Lookup bei jeder
Einreichung aus. Bewusst nur email statt (portal, email) — die Adresse ist
hochselektiv, die Portal-Einschränkung kostet danach nichts mehr, und derselbe
Index trägt zusätzlich die portalübergreifende Gruppierung des
Trockenlauf-Berichts.

ADD INDEX läuft bei InnoDB auch mit vorhandenem FULLTEXT-Index INPLACE, anders
als ADD COLUMN.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
Kevin Adametz 2026-09-01 11:08:06 +00:00
parent e783adc54e
commit a85f6ba15a

View file

@ -0,0 +1,46 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
/**
* B-Tree-Index auf `companies.email`.
*
* `companies` hatte bisher nur `(portal, slug)`, `(portal, is_active)`,
* `(created_at, id)` und einen FULLTEXT über `(name, email, slug)`. Ein
* FULLTEXT-Index beantwortet aber kein `WHERE email = ?` — jede Suche über die
* Firmen-E-Mail war damit ein voller Tabellendurchlauf.
*
* Gebraucht wird der Index für die Newsroom-Konsolidierung (Roadmap Block 1a):
* Die Zusammenführung schlüsselt ausdrücklich über die FIRMEN-E-Mail, nicht
* über die Pressekontaktadresse, und 1a.4 will diesen Lookup bei JEDER
* eingehenden API-Meldung ausführen.
*
* Bewusst nur `email` statt `(portal, email)`: Die Adresse ist hochselektiv,
* die Einschränkung auf das Portal kostet danach nichts mehr — und derselbe
* Index trägt zusätzlich die portalübergreifende Gruppierung des
* Trockenlauf-Berichts (1a.1), was ein zusammengesetzter Index nicht könnte.
*
* Kosten: `ADD INDEX` läuft bei InnoDB auch mit vorhandenem FULLTEXT-Index
* `INPLACE` — anders als `ADD COLUMN`, das dort auf `ALGORITHM=COPY` fällt
* (siehe CLAUDE.md). Bei 70 MB ist das eine Sache von Sekunden.
*/
return new class extends Migration
{
public function up(): void
{
if (Schema::hasColumn('companies', 'email')) {
Schema::table('companies', function (Blueprint $table) {
$table->index('email', 'companies_email_idx');
});
}
}
public function down(): void
{
Schema::table('companies', function (Blueprint $table) {
$table->dropIndex('companies_email_idx');
});
}
};