Data og stabil drift

Store datamængder: få appen til at hente det nødvendige

En app kan føles hurtig med tyve testposter og gå i stå med tusindvis af kunder, produkter eller sager. Den robuste løsning er ikke bare en større server. Hver skærm skal hente et afgrænset, sorteret og adgangskontrolleret udsnit, mens optællinger, søgning og eksport løses efter deres eget behov.

Udgivet 15. september 2026 · Ca. 12 minutters læsetid

Find de skærme, der henter mere end de viser

Begynd med appens faktiske brugerrejser. Åbn browserens netværkspanel og platformens database- eller API-målinger, og sammenhold det viste resultat med det arbejde, som blev udført. En tabel med få synlige rækker bør ikke automatisk kræve hele databasen i browserens hukommelse.

BrugerhandlingTegn på unødigt arbejdeBedre kontrakt
Åbn kundelisteAlle kunder og alle felter hentesEt begrænset udsnit med de viste felter og en fortsættelse
Søg efter produktHele kataloget downloades og filtreres i browserenEt server- eller databaseopslag med grænse og stabil sortering
Vis antal sagerAlle sager læses for at tælle dem lokaltEn aggregation eller en kontrolleret, vedligeholdt tæller
Lav eksportBrowserrequestet venter på hele datasættetEt afgrænset baggrundsjob med status og adgangskontrol

Mål både antal databaseoperationer, overførte bytes, svartid og browserens arbejde. En hurtig lokal database kan skjule, at samme kode bliver dyr eller ustabil gennem netværket og med rigtige datamængder.

Giv hvert endpoint et loft og en tydelig sortering

En listeforespørgsel bør have et bevidst maksimum, relevante filtre og en entydig rækkefølge. Sortering på dato alene er ikke altid entydig, fordi flere poster kan have samme tidspunkt. Tilføj om nødvendigt et stabilt id som sidste sorteringsfelt, så en sidegrænse kan gentages og testes.

  • Afgræns på serveren: Søgning, status, virksomhed og datointerval skal indgå i forespørgslen – ikke først efter alle poster er hentet.
  • Returnér kun nødvendige felter: En liste behøver sjældent noter, store beskrivelser, filmetadata og intern historik for hver række.
  • Bevar adgangskontrollen: Pagination må aldrig gøre en bred forespørgsel sikker. Brugerens virksomhed, rolle og datarelation skal stadig håndhæves i API, databasepolitik eller Security Rules.
  • Beskriv tomt og slut: Klienten skal kunne skelne mellem ingen resultater, sidste side, fejl og en fortsættelse, der kan prøves igen.
Et maksimum i brugerfladen er ikke nok. Hvis API'et stadig accepterer et vilkårligt stort sideantal eller returnerer alle poster uden parameteren, kan en fejl eller et direkte kald omgå beskyttelsen.

Brug en fortsættelse, der passer til datalageret

Pagination betyder, at resultatet hentes i afgrænsede sider. Hvordan næste side findes, afhænger af teknologien. Brug lagerets dokumenterede cursor eller continuation token, når den findes, og send de samme filtre og den samme sortering med igen.

Firestore
Kombinér en begrænset query med en cursor fra den sidste post. Firebase fraråder offsets, fordi de oversprungne dokumenter stadig behandles internt og påvirker både svartid og fakturerede læsninger.
PostgreSQL
LIMIT kræver en forudsigelig ORDER BY. PostgreSQL gør også opmærksom på, at et stort OFFSET kan være ineffektivt, fordi de oversprungne rækker stadig beregnes. Ved dybe lister kan en cursor baseret på de sorterede værdier være bedre.
Azure Table Storage
Bevar continuation token sammen med den oprindelige filter- og feltudvælgelse. Et tomt delresultat kan stadig have en fortsættelse, så stop ikke alene ud fra antallet på den aktuelle side.

En cursor er normalt en teknisk position, ikke en permanent bogmærkeadresse. Hvis klienten ikke længere kan bruge positionen efter ændrede filtre eller data, skal listen kunne genstartes tydeligt frem for at gætte videre.

Søg og tæl uden at hente samlingen

Søgning og optælling er egne databaseopgaver. En browserfiltrering er kun egnet, når hele det afgrænsede datasæt bevidst allerede er lokalt. Ellers skal brugerens kriterier omsættes til en forespørgsel, som datalageret kan udføre sikkert og effektivt.

  • Præcist opslag: Brug stabile nøgler til eksempelvis varenummer, bookingnummer eller id frem for at scanne en liste.
  • Præfiks og filtre: Normalisér de felter, som løsningen faktisk skal søge i, og afgræns resultatet. Krav om vilkårlig deltekst, stavefejl og rangering kan kræve en særskilt søgeløsning.
  • Optælling: Brug databasens aggregation, når den passer. Firestore kan beregne blandt andet count() via indeks og sende selve resultatet i stedet for alle dokumenter.
  • Dashboardtal: Hvis en dyr beregning vises ofte, kan en vedligeholdt summary være relevant. Dokumentér hvornår den opdateres, og hvordan den afstemmes mod kilden.

Indeksér efter de virkelige forespørgsler

Et indeks hjælper databasen med at finde relevante poster uden altid at gennemgå hele tabellen. Det skal passe til filtre, sortering og relationer i de kritiske skærme. Indeks er ikke gratis: de bruger plads og skal vedligeholdes ved skrivninger, så opret dem ud fra målte forespørgsler frem for gæt.

  1. 1. Gem den konkrete langsomme handling: Skærm, filter, datamængde, miljø og tidspunkt.
  2. 2. Find forespørgslen: Kontrollér hvilke tabeller, collections, filtre, sorteringer og joins den bruger.
  3. 3. Undersøg planen: PostgreSQLs EXPLAIN viser den valgte query plan. EXPLAIN ANALYZE udfører forespørgslen, så ændrende statements skal behandles med særlig forsigtighed.
  4. 4. Mål igen: Sammenlign svartid, læste rækker eller dokumenter, overførte bytes og skriveomkostning efter ændringen.
  5. 5. Gem begrundelsen: Knyt indeks og query til en brugerrejse, så en senere oprydning ikke fjerner en usynlig driftsforudsætning.

Undgå skjulte gentagelser og brede realtidslyttere

En afgrænset hovedliste kan stadig blive langsom, hvis appen derefter laver et ekstra opslag for hver række. Kortlæg hele kæden fra sideåbning til sidste databasekald.

  • Gentagne opslag: Saml relaterede data i en passende query, hent nødvendige referencer i batches, eller gem en lille afledt visningsværdi, hvis datamodellen kan holde den korrekt.
  • Realtidslyttere: Lyt kun på det udsnit, skærmen bruger, og luk lytteren når skærmen forlades. Et dashboard behøver ikke nødvendigvis hele historikken i realtid.
  • Cache: Brug kun cache med kendt levetid og ugyldiggørelse. Hurtige, forældede tal er stadig forkerte.
  • Store eksporter: Flyt langvarigt arbejde til et job med status, grænser og en sikker download, hvis et almindeligt request ikke er en stabil ramme.

Test med vækst – ikke kun med flere samtidige brugere

Samtidighed og datamængde er forskellige belastninger. En enkelt bruger kan udløse en dårlig fuld scanning, mens mange brugere kan belaste en ellers velafgrænset query. Test derfor de kritiske lister og søgninger med en realistisk mængde syntetiske eller godkendte testdata i et isoleret miljø.

  • Kontrollér første side, dybe sider, tomme resultater og ændrede filtre.
  • Tilføj nye poster mellem to sidekald, og se efter dubletter eller manglende rækker.
  • Test langsom database, timeout og afbrudt netværk uden at miste brugerens filter og kontekst.
  • Mål med datafordelinger, der ligner virkeligheden; mange poster med samme status eller dato kan opføre sig anderledes end jævnt fordelte demoer.
  • Kontrollér at en anden virksomheds poster aldrig kommer med i browser, cache, eksport eller fejlspor.

PostgreSQLs dokumentation advarer direkte mod at overføre konklusioner fra en meget lille tabel til en stor. Query plannerens valg kan ændre sig med datamængden.

Typiske fejl

  • Alt hentes ved login: Brugeren betaler ventetiden og databaseforbruget, selv om funktionen aldrig åbnes.
  • Søgning sker kun i browseren: Resultatet ser korrekt ud i demoen, men kræver hele kataloget lokalt.
  • En side mangler entydig sortering: Poster springer mellem sider eller vises to gange, når data ændrer sig.
  • Antal beregnes ved at hente alle poster: Et lille dashboardtal bliver den dyreste forespørgsel.
  • Indeks tilføjes uden måling: Skrivninger og lager bliver dyrere, mens den virkelige flaskehals ligger et andet sted.
  • Kun svartid måles: Unødige læsninger, dataoverførsel og browserhukommelse vokser ubemærket.
  • Optimeringen omgår adgangsreglen: En ny global query er hurtig, men kan returnere andre kunders data.

Tjekliste før datamængden vokser

  • ☐ Kritiske lister, søgninger, dashboards og eksporter er kortlagt.
  • ☐ Ingen appstart eller almindelig listeskærm henter hele et voksende datasæt uden et dokumenteret behov.
  • ☐ Hvert liste-endpoint har serverhåndhævet maksimum, filtre og entydig sortering.
  • ☐ Pagination bruger den valgte databases dokumenterede cursor eller continuation token, hvor det passer.
  • ☐ Søgning og optælling udføres af datalageret eller en bevidst afledt model.
  • ☐ Indeks er knyttet til målte forespørgsler, og deres skrive- og lagerpris er forstået.
  • ☐ Gentagne opslag pr. række og brede realtidslyttere er fundet og vurderet.
  • ☐ Målinger forbinder skærm og version med svartid, databasearbejde, dataoverførsel og fejl.
  • ☐ Testmiljøet har realistisk datamængde og dækker ændringer mellem sidekald.
  • ☐ Alle optimerede queries håndhæver virksomhed, rolle og adgang til den konkrete datapost.
  • ☐ Rollback eller feature flag er klar, hvis en ny query giver forkerte eller manglende resultater.

Relaterede guides

Officielle kilder

Rådene er kontrolleret mod aktuelle officielle kilder. Den konkrete query, pagination og måling skal altid tilpasses det datalager og den version, appen faktisk bruger.

Virker appen med demoen, men ikke med jeres rigtige datamængde?

I Startklar kan vi gennemgå de konkrete skærme, queries og forbrug i den stack, appen allerede bruger. Målet er at fjerne brede datalæsninger, bevare adgangskontrollen og dokumentere, hvad løsningen kan holde til.

Se Startklar-forløbet