perf: optimize limitZeroAsAll config retrieval in builders and models#10331
perf: optimize limitZeroAsAll config retrieval in builders and models#10331gr8man wants to merge 3 commits into
Conversation
4168c27 to
b2b44dc
Compare
c9d471b to
eea5862
Compare
|
To prove the performance increase, it would be worth running tests before and after the changes. For example, on 100,000 or more records. The second point: Now it is impossible to change the value of the config at runtime if the connection object is the same. You need to specify this in the documentation. The third. The Edit: Rebase develop branch before PR |
The complexity improvement is self-evident (reducing multiple config lookups per query build down to O(1)). Additionally, benchmarking with 100k+ records wouldn't be relevant here, as this optimization strictly affects the PHP-side query compilation time, not the database execution or fetching speed. |
|
The config has a cache. In some cases, I think this will have little effect on performance. The second point is important, because initially it was possible to change the configuration, but now it is impossible. |
|
php benchmark_limit.php [1] Time taken for 500000 calls to limit(0): 1.0128 seconds [1] Time taken for 500000 calls to limit(0): 0.2106 seconds `<?php require DIR . '/vendor/autoload.php'; use CodeIgniter\Database\BaseBuilder; $count = 500000; $db = new MockConnection([]); echo "--- BENCHMARK: BaseBuilder limit() ---\n"; $start = microtime(true); $builder = new BaseBuilder('my_table', $db); $end = microtime(true); echo "[1] Time taken for {$count} calls to limit(0): " . number_format($time, 4) . " seconds\n"; |
michalsn
left a comment
There was a problem hiding this comment.
The original benchmark reuses the same builder 500k times, which effectively hides the added constructor cost. When construction is included for each builder, this PR is slightly slower in that test.
More importantly, as already mentioned, existing builders and models would no longer see runtime configuration changes.
Even in the ideal best-case scenario, this saves only fractions of a microsecond per operation. I don't think that justifies adding cached state and changing existing behavior.
Description
Currently, a single database query compilation (e.g.,
$builder->get(0)) callsconfig(Feature::class)->limitZeroAsAllmultiple times across methods such aslimit(),get(), andcompileSelect(). Each call passes through theFactories::get()method, which adds unnecessary overhead due to alias resolution and class existence checks.This PR optimizes this behavior by caching the
limitZeroAsAllvalue in a protected property ($limitZeroAsAll) during the class instantiation (in the constructor) forBaseBuilder,Database\SQLSRV\Builder,BaseModel, andModel. This prevents repeated, expensive config lookups when building and executing database queries, eliminating the overhead and improving performance. A new unit test has also been included to verify that the config is only accessed once during query compilation.Checklist: