Skip to content

Allow partial count for findings endpoints - #7035

Merged
nscuro merged 1 commit into
DependencyTrack:mainfrom
nscuro:findings-partial-count
Aug 19, 2026
Merged

Allow partial count for findings endpoints#7035
nscuro merged 1 commit into
DependencyTrack:mainfrom
nscuro:findings-partial-count

Conversation

@nscuro

@nscuro nscuro commented Aug 19, 2026

Copy link
Copy Markdown
Member

Description

Aims to address scenarios where the portfolio size (number of projects and / or findings) prevents the global findings search endpoints from completing in a reasonable time frame.

Addressed Issue

Fixes #6570

Additional Details

Frontend PR: DependencyTrack/frontend#1756
Docs PR: DependencyTrack/docs#228

I did lots of testing with portfolios of up to 100M findings, and there is no solution that works for all possible filter and sorting options. Fundamentally the endpoints present an OLAP workload, for which a transactional DB is unfit no matter how we turn it. Usually this is where one would reach for separate infra (OpenSearch, ClickHouse), but this being an on-prem OSS application with varying portfolio sizes, that's not justifiable by any means.

What I ended up settling for is a solution composed of two pieces:

  • Adopt the concept of partial counts in API v1. Counting is the most expensive part here, because it forces Postgres to materialize the full result set before it can return data. The endpoints now support an (optional) totalCount query parameter where clients can opt in to partial counts to improve performance. I couldn't make it the default because it would've been a breaking change. For both non-grouped endpoints, counting caps at 10k. The grouped endpoint has no affordable count at all, and reports only a number the requested page can prove. See ADR 036 for details.
  • Optimize the backing queries further, e.g. by separating sorting and filtering from enrichment to make the former cheaper.

While working on this I kept asking myself "why don't we just denormalize all this crap?", but always ended up discarding it for consistency and write amplification concerns. Created ADR 037 to document this for the future.

Checklist

  • I have read and understand the contributing guidelines
  • This PR fixes a defect, and I have provided tests to verify that the fix is effective
  • This PR implements an enhancement, and I have provided tests to verify that it works as intended
  • This PR introduces changes to the database model, and I have updated the migration changelog accordingly
  • This PR introduces new or alters existing behavior, and I have updated the documentation accordingly
  • This PR is a substantial change (per the ADR criteria), and I have added an ADR under docs/adr/

Aims to address scenarios where the portfolio size (number of projects and / or findings) prevents the global findings search endpoints from completing in a reasonable time frame.

I did lots of testing with portfolios of up to 100M findings, and there is no solution that works for all possible filter and sorting options. Fundamentally the endpoints present an OLAP workload, for which a transactional DB is unfit no matter how we turn it. Usually this is where one would reach for separate infra (OpenSearch, ClickHouse), but this being an on-prem OSS application with varying portfolio sizes, that's not justifiable by any means.

What I ended up settling for is a solution composed of two pieces:

* Adopt the concept of partial counts in API v1. Counting is the most expensive part here, because it forces Postgres to materialize the full result set before it can return data. The endpoints now support an (optional) `totalCount` query parameter where clients can opt in to partial counts to improve performance. I couldn't make it the default because it would've been a breaking change. For both non-grouped endpoints, counting caps at 10k. The grouped endpoint has no affordable count at all, and reports only a number the requested page can prove. See ADR 036 for details.
* Optimize the backing queries further, e.g. by separating sorting and filtering from enrichment to make the former cheaper.

While working on this I kept asking myself "why don't we just denormalize all this crap?", but always ended up discarding it for consistency and write amplification concerns. Created ADR 037 to document this for the future.

Signed-off-by: nscuro <nscuro@protonmail.com>
@nscuro nscuro added this to the 5.1 milestone Aug 19, 2026
@nscuro nscuro added the defect Something isn't working label Aug 19, 2026
@owasp-dt-bot

Copy link
Copy Markdown

Snyk checks have passed. No issues have been found so far.

Status Scan Engine Critical High Medium Low Total (0)
Open Source Security 0 0 0 0 0 issues

💻 Catch issues earlier using the plugins for VS Code, JetBrains IDEs, Visual Studio, and Eclipse.

@codacy-production

codacy-production Bot commented Aug 19, 2026

Copy link
Copy Markdown

Up to standards ✅

🟢 Issues 0 issues

Results:
0 new issues

View in Codacy

🟢 Metrics 14 complexity

Metric Results
Complexity 14

View in Codacy

🟢 Coverage 97.16% diff coverage · +0.02% coverage variation

Metric Results
Coverage variation +0.02% coverage variation (-1.00%)
Diff coverage 97.16% diff coverage (70.00%)

View coverage diff in Codacy

Coverage variation details
Coverable lines Covered lines Coverage
Common ancestor commit (3573b5a) 44410 38722 87.19%
Head commit (748b0c7) 44504 (+94) 38815 (+93) 87.22% (+0.02%)

Coverage variation is the difference between the coverage for the head and common ancestor commits of the pull request branch: <coverage of head commit> - <coverage of common ancestor commit>

Diff coverage details
Coverable lines Covered lines Diff coverage
Pull request (#7035) 141 137 97.16%

Diff coverage is the percentage of lines that are covered by tests out of the coverable lines that the pull request added or modified: <covered lines added or modified>/<coverable lines added or modified> * 100%

NEW Get contextual insights on your PRs based on Codacy's metrics, along with PR and Jira context, without leaving GitHub. Enable AI reviewer
TIP This summary will be updated as you push new changes.

@nscuro
nscuro merged commit 2850a51 into DependencyTrack:main Aug 19, 2026
24 checks passed
@nscuro
nscuro deleted the findings-partial-count branch August 19, 2026 12:42
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

defect Something isn't working

Projects

None yet

Development

Successfully merging this pull request may close these issues.

apiserver: "Failed to load table data" when opening "Vulnerability Audit" page

2 participants