From 8e8a70b9c7324a99974e32224c8f07897e6586c7 Mon Sep 17 00:00:00 2001 From: Git'Fellow <12234510+solracsf@users.noreply.github.com> Date: Wed, 3 Jun 2026 09:57:00 +0200 Subject: [PATCH] perf(folder): avoid on-disk temp table when sorting folders by group count Signed-off-by: Git'Fellow <12234510+solracsf@users.noreply.github.com> --- lib/Folder/FolderManager.php | 18 ++++++++++++---- tests/Folder/FolderManagerTest.php | 34 ++++++++++++++++++++++++++++++ 2 files changed, 48 insertions(+), 4 deletions(-) diff --git a/lib/Folder/FolderManager.php b/lib/Folder/FolderManager.php index 16becb23b..7e98cfdb1 100644 --- a/lib/Folder/FolderManager.php +++ b/lib/Folder/FolderManager.php @@ -144,10 +144,20 @@ public function getAllFoldersWithSize(int $offset = 0, ?int $limit = null, strin $query->setFirstResult($offset); $query->setMaxResults($limit); if ($orderBy === 'groups') { - $query - ->leftJoin('f', 'group_folders_groups', 'g', $query->expr()->eq('f.folder_id', 'g.folder_id')) - ->groupBy('f.folder_id') - ->orderBy($query->func()->count('g.applicable_id'), $order); + // Order by the number of groups/circles applicable to each folder. + // + // We deliberately avoid a "JOIN group_folders_groups + GROUP BY f.folder_id" + // here. Grouping forces the database to materialize an internal temporary + // table, and because the selected `options` column is a LONGTEXT that + // temporary table cannot use the in-memory MEMORY engine, so MariaDB/MySQL + // always spills it to an on-disk (Aria) temp table regardless of + // `tmp_table_size`. A correlated sub-query yields the same ordering without + // grouping the wide result set, so no temporary table is created. + $countSubQuery = $this->connection->getQueryBuilder(); + $countSubQuery->select($countSubQuery->func()->count('g.applicable_id')) + ->from('group_folders_groups', 'g') + ->where($countSubQuery->expr()->eq('g.folder_id', 'f.folder_id')); + $query->orderBy($query->createFunction('(' . $countSubQuery->getSQL() . ')'), $order); } else { $query->orderBy($orderBy, $order); } diff --git a/tests/Folder/FolderManagerTest.php b/tests/Folder/FolderManagerTest.php index eda4f24ee..4a9fb88ca 100644 --- a/tests/Folder/FolderManagerTest.php +++ b/tests/Folder/FolderManagerTest.php @@ -13,6 +13,7 @@ use OCA\GroupFolders\Folder\FolderDefinition; use OCA\GroupFolders\Folder\FolderDefinitionWithPermissions; use OCA\GroupFolders\Folder\FolderManager; +use OCA\GroupFolders\Folder\FolderWithMappingsAndCache; use OCA\GroupFolders\Mount\FolderStorageManager; use OCA\GroupFolders\ResponseDefinitions; use OCP\Constants; @@ -517,4 +518,37 @@ public function testQuotaDefaultValue(): void { } $this->assertEquals(1024 ** 4, $folder->quota); } + + public function testGetAllFoldersWithSizeOrderedByGroups(): void { + $this->config->expects($this->any()) + ->method('getSystemValueInt') + ->with('groupfolders.quota.default', FileInfo::SPACE_UNLIMITED) + ->willReturn(FileInfo::SPACE_UNLIMITED); + + // Create folders with a different number of applicable groups each. + $oneGroup = $this->manager->createFolder('one-group'); + $threeGroups = $this->manager->createFolder('three-groups'); + $twoGroups = $this->manager->createFolder('two-groups'); + + $this->manager->addApplicableGroup($oneGroup, 'g1'); + + $this->manager->addApplicableGroup($twoGroups, 'g1'); + $this->manager->addApplicableGroup($twoGroups, 'g2'); + + $this->manager->addApplicableGroup($threeGroups, 'g1'); + $this->manager->addApplicableGroup($threeGroups, 'g2'); + $this->manager->addApplicableGroup($threeGroups, 'g3'); + + $ascending = array_map( + fn (FolderWithMappingsAndCache $folder): string => $folder->mountPoint, + array_values($this->manager->getAllFoldersWithSize(0, null, 'groups', 'ASC')), + ); + $this->assertEquals(['one-group', 'two-groups', 'three-groups'], $ascending); + + $descending = array_map( + fn (FolderWithMappingsAndCache $folder): string => $folder->mountPoint, + array_values($this->manager->getAllFoldersWithSize(0, null, 'groups', 'DESC')), + ); + $this->assertEquals(['three-groups', 'two-groups', 'one-group'], $descending); + } }