Skip to content

refactor: Allow SQL to do recursive search for files in subfolders#6582

Merged
valadas merged 3 commits intodnnsoftware:developfrom
timi-ty:fix/slow_file_search
Jun 15, 2025
Merged

refactor: Allow SQL to do recursive search for files in subfolders#6582
valadas merged 3 commits intodnnsoftware:developfrom
timi-ty:fix/slow_file_search

Conversation

@timi-ty
Copy link
Copy Markdown
Contributor

@timi-ty timi-ty commented Jun 6, 2025

Summary

Eliminates excessive database load during file searches by making a single recursive call instead of one per sub-folder.


Problem statement

On portals with deep folder hierarchies every search triggers N × dbo.GetFiles calls (N = folder count). Though each query costs < 35 ms CPU, thousands executed serially drive SQL Server to 100 % CPU and users wait ~1 minute.


Implementation details

  • Propagate the recursive flag to GetFiles.
  • Consolidate result filtering & permission checks in memory.
  • No DB schema changes, no new indexes, no public API changes.
  • Existing unit tests remain green.

Performance results

Metric (67 k files / 2 700 folders) Before After
Total runtime (search “d”) ~60 s ~2 s
DB calls to GetFiles ~2 700 5
SQL CPU utilisation 100 % < 15 %

Test plan

  1. Seed sample portal.
  2. Search “d” in Global Assets and record timings/logs.
  3. Run DotNetNuke.Tests.Core.Providers.Folder – all pass.

Evidence

Before Fix

DNN_Search_For_d_57_secs_original.mp4

After Fix

DNN_Search_For_d_2_secs.mp4

@mitchelsellers
Copy link
Copy Markdown
Contributor

@timi-ty Thank you so much for such a detailed submission, we will be sure to get this reviewed as quickly as possible

Copy link
Copy Markdown
Contributor

@bdukes bdukes left a comment

Choose a reason for hiding this comment

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

This is a great contribution, thanks for the robust write up and investigation.

files.AddRange(this.SearchFiles(subFolder, regex, true));
}
}
return fileCollection.Where(f => regex.IsMatch(f.FileName)).Cast<IFileInfo>();
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 method used to return a List and now it returns an IEnumerable. In the usages within DNN itself, this appears to be a performance boost, since the two callers do sorting and then materialize the results into a list (thus, this change avoids materializing the list an extra time).

It's possible that 3rd party usages of this method will be less performant if there were reusing the returned collection, but I think the benefit it higher than the drawback.

timi-ty and others added 2 commits June 7, 2025 08:13
@bdukes bdukes added this to the 10.0.2 milestone Jun 7, 2025
Copy link
Copy Markdown
Contributor

@valadas valadas left a comment

Choose a reason for hiding this comment

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

It looks good to me, I would just like to give this a test with folder providers before merging

@valadas
Copy link
Copy Markdown
Contributor

valadas commented Jun 15, 2025

Ok, I just tested with an Azure folder provider with a lot of subfoldes and file and performance was great. Merci. Thanks @timi-ty

@valadas valadas merged commit 7ffa603 into dnnsoftware:develop Jun 15, 2025
3 checks passed
@valadas valadas modified the milestones: 10.0.2, 10.1.0 Jul 30, 2025
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