Skip to content

perf: Enhance objects using constant sql queries count to get rid of N+1 queries - #2857

Open
Koc wants to merge 3 commits into
mainfrom
feature/optimize-enhance-tables
Open

Koc wants to merge 3 commits into
mainfrom
feature/optimize-enhance-tables

Conversation

@Koc

@Koc Koc commented Jul 29, 2026 •

Copy link
Copy Markdown
Contributor

In our organization we operate a large amount of tables/views, so there are performance bottleneck here:

PERFORMANCE: Controller OCA\\Tables\\Controller\\Api1Controller::index executed 1883 queries in 20.1 seconds
PERFORMANCE: Controller OCA\\Tables\\Controller\\TableController::index executed 1887 queries in 16.6 seconds
  • Replaced TableService::enhanceTable() in a loop with a single call of the enhanceTables()
  • Replaced ViewService::enhanceView() in a loop with a single call of theenhanceViews()
  • Added batch helpers in mappers/services and UserHelper for row/column counts, share counts and owner display names.

🖼️ Screenshots

Here profiler results for GET /apps/tables/table endpoint for 18 tables and 9 views:

🏚️ Before 🏡 After
121 queries 29 queries
image image

🏁 Checklist

  • ⛑️ Tests (unit and/or integration) are included or not needed
  • 🔙 Backport requests are created or not needed: /backport to stableX.X
  • 📅 Milestone is set
  • 🌸 PR title is meaningful (if it should be in the changelog: is it meaningful to users?)

🤖 AI (if applicable)

  • The content of this PR was partly or fully generated using AI

@Koc
Koc force-pushed the feature/optimize-enhance-tables branch 2 times, most recently from 9b6bd68 to 4033598 Compare July 29, 2026 00:28
@Koc
Koc marked this pull request as ready for review July 29, 2026 18:08
@Koc
Koc requested review from blizzz and enjeck as code owners July 29, 2026 18:08
@Koc Koc changed the title perf: Call enhanceTables for a multiple tables at once to get rid of N+1 queries perf: Enhance objects for a multiple tables at once to get rid of N+1 queries Jul 29, 2026
@Koc Koc changed the title perf: Enhance objects for a multiple tables at once to get rid of N+1 queries perf: Enhance objects using constant sql queries count to get rid of N+1 queries Jul 29, 2026
@Koc
Koc force-pushed the feature/optimize-enhance-tables branch 2 times, most recently from 29cbb47 to 44e315b Compare July 29, 2026 21:57
Comment thread lib/Db/ShareMapper.php Outdated
Comment thread lib/Service/ViewService.php Outdated
Comment thread lib/Db/RowSleeveMapper.php Outdated
Comment thread lib/Controller/Api1Controller.php Outdated
@Koc
Koc force-pushed the feature/optimize-enhance-tables branch 2 times, most recently from 2686136 to e9b83fb Compare August 9, 2026 14:30
@Koc
Koc requested a review from enjeck August 9, 2026 14:46
@samin-z
samin-z self-requested a review August 10, 2026 15:48
@Koc
Koc force-pushed the feature/optimize-enhance-tables branch from e9b83fb to b286459 Compare August 24, 2026 00:51
Comment thread lib/Db/ShareMapper.php Outdated
Comment thread lib/Controller/Api1Controller.php
Comment thread lib/Service/ShareService.php
Comment thread lib/Controller/Api1Controller.php
Comment thread lib/Db/ColumnMapper.php
Comment thread lib/Db/ViewMapper.php Outdated
@Koc
Koc force-pushed the feature/optimize-enhance-tables branch 2 times, most recently from 306f894 to f5cb044 Compare August 27, 2026 23:58
@Koc
Koc force-pushed the feature/optimize-enhance-tables branch 2 times, most recently from a7383f5 to c9e19d1 Compare August 30, 2026 14:27
@Koc

Koc commented Aug 30, 2026 •

Copy link
Copy Markdown
Contributor Author

@enjeck I've fixed conflicts introduced by #2781 and code review comments, please, check one more time.

@enjeck enjeck left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

a question:

Comment thread lib/Db/RowSleeveMapper.php Outdated
@enjeck
enjeck force-pushed the feature/optimize-enhance-tables branch from 263e65c to ba01275 Compare September 4, 2026 04:44
@Koc
Koc force-pushed the feature/optimize-enhance-tables branch from ba01275 to ecef56b Compare September 4, 2026 08:27
@Koc
Koc requested a review from enjeck September 4, 2026 09:05
@Koc
Koc force-pushed the feature/optimize-enhance-tables branch 2 times, most recently from 7243f39 to e845c15 Compare September 12, 2026 15:42

@blizzz blizzz 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.

Some questions, and view ordering got lost it seems

Comment thread lib/Db/ViewMapper.php Outdated
* @param array<int, int|null> $tableRowsCounts
*/
private function enhanceViews(array $views, string $userId, array $tableRowsCounts = []): void {
if (empty($views)) {

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.

this does not have the isFederated guard anymore. Intentional? It puts the responsibility to check about it to the caller, like in enhanceView() currently.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

I've added behat test for that, please check

Comment thread lib/Service/ShareService.php Outdated

try {
$excluded = !$this->circleHelper->isCirclesEnabled() ? [ShareReceiverType::CIRCLE] : [];
$shares = $this->mapper->findAllSharesForNodes('table', $tableIds, $userId, $excluded);

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.

Does this still find all shares for a table manager, i.e. indirect shares?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

I've added behat test for that, please check

Comment thread lib/Service/TableService.php Outdated
@Koc
Koc force-pushed the feature/optimize-enhance-tables branch from e845c15 to ecef56b Compare September 16, 2026 22:53
@Koc
Koc force-pushed the feature/optimize-enhance-tables branch from ecef56b to abc0f82 Compare September 16, 2026 22:54
@Koc
Koc force-pushed the feature/optimize-enhance-tables branch 4 times, most recently from ef7479b to e460edf Compare October 9, 2026 21:01
@Koc

Koc commented Oct 9, 2026

Copy link
Copy Markdown
Contributor Author

@blizzz I've fixed code review comments, please check

@Koc
Koc requested a review from blizzz October 9, 2026 22:17
@enjeck
enjeck force-pushed the feature/optimize-enhance-tables branch from e460edf to b5cf342 Compare October 17, 2026 14:38
Koc added 3 commits October 18, 2026 19:26
…N+1 queries

Signed-off-by: Kostiantyn Miakshyn <molodchick@gmail.com>
…N+1 queries (code review new portion)

Signed-off-by: Kostiantyn Miakshyn <molodchick@gmail.com>
…N+1 queries (more tests)

Signed-off-by: Kostiantyn Miakshyn <molodchick@gmail.com>
@Koc
Koc force-pushed the feature/optimize-enhance-tables branch from b5cf342 to 70976c6 Compare October 18, 2026 17:26

@enjeck enjeck left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

I have some more comments:

Comment on lines +106 to +107
try {
$allViews = $this->mapper->findAllByTableIds($tableIds);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

findForTables() dropped the canManageTable() check from the old findAll(). I think this causes a read-only sharee calling GET /api/2/tables/scheme/{id} gets 200 with all views and their filters ??

public function getScheme(int $id, ?string $userId = null): TableScheme {
$table = $this->find($id, skipTableEnhancement: true);
$columns = $this->columnService->findAllByTable($id, null, $table);
$this->enhanceTable($table, $userId ?? '');

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Should this be preCheckUserId($userId) instead?

Comment on lines +144 to +147
try {
$this->enhanceTables($allTables, $userId);
} catch (InternalError|PermissionError $e) {
$this->logger->error($e->getMessage(), ['exception' => $e]);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

One exception here now skips enhancement for every table. Can each step handle its own errors like before?

Comment thread lib/Db/ColumnMapper.php
$this->logger->warning('Exception occurred: ' . $e->getMessage() . ' Returning 0.');
return 0;
$counts = array_fill_keys($tableIds, 0);
foreach (array_chunk($tableIds, 1000 - 1) as $tableIdsChunk) {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Can we build the query once outside the loop and use a DB_CHUNK_SIZE constant?

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

same in ther places

Comment thread lib/Db/ShareMapper.php
* @param int[] $tableIds
* @return int[]
*/
public function findLinkSharesForTables(array $tableIds): array {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Suggested change
public function findLinkSharesForTables(array $tableIds): array {
public function findTableIdsWithLinkShares(array $tableIds): array {

* @return array<int, int>
* @throws InternalError
*/
public function countSharesForTables(array $tableIds): array {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

This duplicates countSharesForViews(). Could they merge into one countSharesForNodes($nodeType, $nodeIds)? Or is that too hard ?

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

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants