Skip to content

perf: optimize limitZeroAsAll config retrieval in builders and models#10331

Closed
gr8man wants to merge 3 commits into
codeigniter4:developfrom
gr8man:perf/optimize-limitZeroAsAll
Closed

perf: optimize limitZeroAsAll config retrieval in builders and models#10331
gr8man wants to merge 3 commits into
codeigniter4:developfrom
gr8man:perf/optimize-limitZeroAsAll

Conversation

@gr8man

@gr8man gr8man commented Jun 21, 2026

Copy link
Copy Markdown
Contributor

Description
Currently, a single database query compilation (e.g., $builder->get(0)) calls config(Feature::class)->limitZeroAsAll multiple times across methods such as limit(), get(), and compileSelect(). Each call passes through the Factories::get() method, which adds unnecessary overhead due to alias resolution and class existence checks.
This PR optimizes this behavior by caching the limitZeroAsAll value in a protected property ($limitZeroAsAll) during the class instantiation (in the constructor) for BaseBuilder, Database\SQLSRV\Builder, BaseModel, and Model. 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:

  • Securely signed commits
  • Component(s) with PHPDoc blocks, only if necessary or adds value (without duplication)
  • Unit testing, with >80% coverage
  • User guide updated
  • Conforms to style guide

@gr8man gr8man force-pushed the perf/optimize-limitZeroAsAll branch from 4168c27 to b2b44dc Compare June 21, 2026 22:34
@gr8man gr8man force-pushed the perf/optimize-limitZeroAsAll branch from c9d471b to eea5862 Compare June 21, 2026 22:40
@neznaika0

neznaika0 commented Jun 22, 2026

Copy link
Copy Markdown
Contributor

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 Feature config was previously replaced and its settings were transferred to the main code. Perhaps it can already be adapted by transferring it to the Database?

Edit: Rebase develop branch before PR

@gr8man

gr8man commented Jun 22, 2026

Copy link
Copy Markdown
Contributor Author

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 Feature config was previously replaced and its settings were transferred to the main code. Perhaps it can already be adapted by transferring it to the Database?

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.

@neznaika0

Copy link
Copy Markdown
Contributor

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.

@gr8man gr8man closed this Jun 22, 2026
@gr8man gr8man reopened this Jun 30, 2026
@gr8man

gr8man commented Jun 30, 2026

Copy link
Copy Markdown
Contributor Author

php benchmark_limit.php
--- BENCHMARK: BaseBuilder limit() ---
Current Branch: develop
Iterations: 500,000

[1] Time taken for 500000 calls to limit(0): 1.0128 seconds
gr8man@hp255r:~/Publiczny/codeigniter/CodeIgniter4$ php benchmark_limit.php
--- BENCHMARK: BaseBuilder limit() ---
Current Branch: perf/optimize-limitZeroAsAll
Iterations: 500,000

[1] Time taken for 500000 calls to limit(0): 0.2106 seconds

`<?php

require DIR . '/vendor/autoload.php';
require DIR . '/system/Test/bootstrap.php';

use CodeIgniter\Database\BaseBuilder;
use CodeIgniter\Test\Mock\MockConnection;

$count = 500000;

$db = new MockConnection([]);

echo "--- BENCHMARK: BaseBuilder limit() ---\n";
echo "Current Branch: " . trim(shell_exec('git rev-parse --abbrev-ref HEAD')) . "\n";
echo "Iterations: " . number_format($count) . "\n\n";

$start = microtime(true);

$builder = new BaseBuilder('my_table', $db);
for ($i = 0; $i < $count; $i++) {
$builder->limit(0);
}

$end = microtime(true);
$time = $end - $start;

echo "[1] Time taken for {$count} calls to limit(0): " . number_format($time, 4) . " seconds\n";
`

@michalsn michalsn left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.

@gr8man gr8man closed this Jul 1, 2026
@gr8man gr8man deleted the perf/optimize-limitZeroAsAll branch July 1, 2026 17:52
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants