From 6a406bf5774f053b66a60b150a583742b7025354 Mon Sep 17 00:00:00 2001 From: Kevin Adametz Date: Tue, 30 Jun 2026 11:30:49 +0000 Subject: [PATCH] Perf: accessibleBy() nutzt company_id-Subquery statt materialisiertem whereIn MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit scopeAccessibleBy() haengte den Firmenzugriff bisher als whereIn() mit allen via accessibleCompanyIds() materialisierten Firmen-IDs an. Bei Power-Usern (26k+ Firmen) ist das ein riesiger IN-Block im SQL. Jetzt: orWhereIn('company_id', Company::accessibleBy($user)->select('id')) — MySQL loest die Subquery als Semi-Join ueber den company_id-Index. Gleiche Semantik (Company-Global-Scopes werden mitkompiliert), aber beschraenkte SQL-Groesse und keine PHP-seitige ID-Liste mehr. Benchmark (User 14016): ein korreliertes orWhereHas-EXISTS war ~3x langsamer (1070ms vs 335ms COUNT) — die Subquery-whereIn-Form ist die schnellste. accessibleCompanyIds() bleibt fuer canAccessCompany() erhalten. Co-Authored-By: Claude Opus 4.8 (1M context) --- app/Models/PressRelease.php | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/app/Models/PressRelease.php b/app/Models/PressRelease.php index 07a3feb9..f5aeceea 100644 --- a/app/Models/PressRelease.php +++ b/app/Models/PressRelease.php @@ -229,15 +229,16 @@ class PressRelease extends Model */ public function scopeAccessibleBy(Builder $query, User $user): Builder { + // company_id IN () statt eines materialisierten whereIn() mit + // zehntausenden IDs: MySQL loest das als Semi-Join ueber den company_id- + // Index (im Benchmark ~3x schneller als ein korreliertes orWhereHas- + // EXISTS). Company::accessibleBy() (Owner ODER Pivot-Mitglied) ist die + // Single Source of Truth; als Eloquent-Subquery werden die Company- + // Global-Scopes (PortalScope, SoftDeletes) mitkompiliert. return $query->withoutGlobalScopes() ->where(function (Builder $q) use ($user): void { - $q->where('user_id', $user->id); - - $companyIds = $user->accessibleCompanyIds(); - - if ($companyIds !== []) { - $q->orWhereIn('company_id', $companyIds); - } + $q->where('user_id', $user->id) + ->orWhereIn('company_id', Company::accessibleBy($user)->select('companies.id')); }); }