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.
| Brugerhandling | Tegn på unødigt arbejde | Bedre kontrakt |
|---|---|---|
| Åbn kundeliste | Alle kunder og alle felter hentes | Et begrænset udsnit med de viste felter og en fortsættelse |
| Søg efter produkt | Hele kataloget downloades og filtreres i browseren | Et server- eller databaseopslag med grænse og stabil sortering |
| Vis antal sager | Alle sager læses for at tælle dem lokalt | En aggregation eller en kontrolleret, vedligeholdt tæller |
| Lav eksport | Browserrequestet venter på hele datasættet | Et 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.
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
LIMITkræver en forudsigeligORDER BY. PostgreSQL gør også opmærksom på, at et stortOFFSETkan 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. Gem den konkrete langsomme handling: Skærm, filter, datamængde, miljø og tidspunkt.
- 2. Find forespørgslen: Kontrollér hvilke tabeller, collections, filtre, sorteringer og joins den bruger.
- 3. Undersøg planen: PostgreSQLs
EXPLAINviser den valgte query plan.EXPLAIN ANALYZEudfører forespørgslen, så ændrende statements skal behandles med særlig forsigtighed. - 4. Mål igen: Sammenlign svartid, læste rækker eller dokumenter, overførte bytes og skriveomkostning efter ændringen.
- 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.
- Firebase: Best practices for Cloud Firestore
- Firebase: Pagination med query cursors
- Firebase: Optællinger og andre aggregation queries
- PostgreSQL: Introduktion til indeks
- PostgreSQL: LIMIT og OFFSET
- PostgreSQL: Undersøg forespørgsler med EXPLAIN
- Microsoft: Forespørgsler og pagination i Azure Table Storage
- Microsoft: Query timeout og continuation tokens i Azure Table Storage
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