Altinn / Altinn/altinn-authentication

Paginerte request-spørringer mangler LIMIT og leser hele settet per side

Open
#2,177 0 comments 0 reactions 1 assignee Claimed by @howieandersen View on GitHub
performance
Dominant language
C#
Stars
8
Forks
6
Avg merge
2d 21h
Merged PRs (30d)
21

Description

## Beskrivelse

Spørringene som mater de paginerte leverandørendepunktene i `RequestRepository` har ingen `LIMIT`. De henter hele det gjenstående settet fra databasen, materialiserer det i minnet, og først deretter klipper `Page.Create` resultatet ned til sidestørrelsen. Sidestørrelsen når altså aldri fram til databasen.

`grep -c LIMIT src/Persistance/RepositoryImplementations/RequestRepository.cs` gir null treff.

## Hvor

`src/Persistance/RepositoryImplementations/RequestRepository.cs`

- `GetAllRequestsBySystem` linje 525
- `GetAllAgentRequestsBySystem` linje 608

Begge er formet slik, uten noen øvre grense:

```sql
FROM business_application.request r
WHERE r.system_id = @system_id
and r.id > @continue_from
and r.is_deleted = false
and systemuser_type = @systemuser_type
ORDER BY r.id ASC;
```

Konsumentene er `src/Authentication/Services/RequestSystemUserService.cs` linje 793 og 824:

```csharp
List? theList = await requestRepository.GetAllRequestsBySystem(systemId, nextId, cancellationToken);
theList ??= [];

return Page.Create(theList, _paginationSize, static theList => theList.Id);
```

`_paginationSize` (linje 47) kommer fra `PaginationOptions.Size` og brukes bare til å klippe listen etterpå.

## Konsekvens

Med N requests for et system og sidestørrelse P koster det N/P kall å paginere gjennom alt, og hvert kall leser omtrent hele det gjenstående settet. Samlet blir det i størrelsesorden N²/P rader lest fra databasen for én gjennomgang, pluss tilsvarende deserialisering og minnebruk i appen.

Dette er sannsynligvis årsaken bak Altinn/altinn-authentication#1919, der `PaginationOptions.Size` ble hevet fra 50 til 1500 og CPU-bruken i prod falt med 75 prosent. Å heve sidestørrelsen kutter antall runder med 30 og dermed mesteparten av dobbeltarbeidet, men kostnaden er fortsatt kvadratisk, bare delt på en større konstant. Vokser antall requests per system videre, kommer problemet tilbake.

## Forslag

Send sidestørrelsen ned i repository-laget og legg på `LIMIT` i spørringene. Hent gjerne ett element ekstra utover sidestørrelsen for å avgjøre om det finnes en neste side, slik `Page.Create` trenger. Da blir kostnaden lineær, og `PaginationOptions.Size` kan settes tilbake til en mer moderat verdi enn 1500, som er en stor endring av API-kontrakten utad.

Verdt å gå gjennom de øvrige spørringene i samme fil samtidig, siden ingen av dem har `LIMIT`.

## Akseptansekriterier

- `GetAllRequestsBySystem` og `GetAllAgentRequestsBySystem` begrenser antall rader i selve SQL-spørringen
- Sidestørrelsen fra `PaginationOptions` styrer grensen i databasen, ikke bare klippingen etterpå
- Paginering gjennom et stort sett leser hver rad i størrelsesorden én gang
- Test som dekker at neste side beregnes riktig når det finnes akkurat like mange rader som sidestørrelsen

Contributor guide

No contributing guide indexed for this repository

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.