Skip to content

perf: cache SQL schema descriptors and add operation discovery fast-path#876

Open
Remo wants to merge 3 commits into
flat3:5.xfrom
ortic:performance-optimization-pr-v2
Open

perf: cache SQL schema descriptors and add operation discovery fast-path#876
Remo wants to merge 3 commits into
flat3:5.xfrom
ortic:performance-optimization-pr-v2

Conversation

@Remo
Copy link
Copy Markdown
Contributor

@Remo Remo commented May 7, 2026

Item 1 (SQLSchema): Replace the old two-step approach (cache raw DBAL Table, re-process columns every request) with a fully cached pipeline. The new buildPropertyDescriptors() stores a serializable array of type names, nullability, and default values. discoverProperties() hydrates these into OData DeclaredProperty objects without touching the database again on cache hits.

Item 5 (Operation): Add an early-exit in Operation::discover() that checks for any LodataOperation attributes before doing the full per-method reflection scan. Models without operations (the common case) return immediately.

Remo added 3 commits May 7, 2026 10:52
Item 1 (SQLSchema): Replace the old two-step approach (cache raw DBAL Table,
re-process columns every request) with a fully cached pipeline. The new
buildPropertyDescriptors() stores a serializable array of type names, nullability,
and default values. discoverProperties() hydrates these into OData DeclaredProperty
objects without touching the database again on cache hits.

Item 5 (Operation): Add an early-exit in Operation::discover() that checks for any
LodataOperation attributes before doing the full per-method reflection scan.
Models without operations (the common case) return immediately.
The descriptor cache in SQLSchema bypasses columnToDeclaredProperty(),
but EloquentEntitySet overrides that method to apply hidden/visible
filters and Eloquent cast type overrides (e.g. 'array' → collection).
Without that hook, array-cast columns reach String_::set() and trip
"Array to string conversion".

Override discoverProperties() in EloquentEntitySet with the upstream
per-column flow so the cast and visibility logic runs. Pure
SQLEntitySet still uses the new descriptor cache. Revert the redis
discovery test to expect the legacy Table-cache key for Eloquent.
phpstan no longer reports an error on the suppressed line, so the
ignore directive trips the non-ignorable ignore.unmatchedLine rule
and fails the Analysis CI job.
@27pchrisl
Copy link
Copy Markdown
Contributor

@AHolzerSCT can you test this branch in your application to double-check?

@AHolzerSCT
Copy link
Copy Markdown

@Remo @27pchrisl I tested it today. Everything seems to be working just fine, but I do actually loose the biggest portion of the improvements:

  1. Test with performance-optimization-pr-v2 -> Simple GET /odata/Plants -> averaging at about 0.9s
  2. Test with performance-optimization-pr -> Simple GET /odata/Plants -> averaging at about 0.45s
  3. Test with our current Version 5.33.5 -> Simple GET /odata/Plants -> averaging at about 1.1s
  4. Test with custom api -> GET /api/Plants -> averaging at around 0.03s

@Remo
Copy link
Copy Markdown
Contributor Author

Remo commented May 12, 2026

@AHolzerSCT I guess this is not something you could easily publish as a test case so that we can have a closer look?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Development

Successfully merging this pull request may close these issues.

3 participants