sql >> Database teknologi >  >> RDS >> PostgreSQL

Hvordan virker COPY, og hvorfor er det så meget hurtigere end INSERT?

Der er en række faktorer, der spiller ind her:

  • Netværksforsinkelse og tur-retur-forsinkelser
  • Per-state overhead i PostgreSQL
  • Kontekstskift og planlægningsforsinkelser
  • COMMIT omkostninger, hvis for folk, der laver én commit pr. indstik (det er du ikke)
  • COPY -specifikke optimeringer til bulk loading

Netværksforsinkelse

Hvis serveren er ekstern, "betaler" du muligvis en fast tids-"pris" pr. udsagn på f.eks. 50 ms (1/20 af et sekund). Eller meget mere for nogle cloud-hostede DB'er. Da den næste indsættelse ikke kan begynde, før den sidste er fuldført, betyder det din maksimum hastigheden af ​​indsættelser er 1000/tur-retur-latens-i-ms rækker pr. sekund. Ved en latenstid på 50 ms ("pingtid") er det 20 rækker/sekund. Selv på en lokal server er denne forsinkelse ikke nul. Hvorimod COPY udfylder bare TCP sende og modtage vinduer, og streamer rækker så hurtigt som DB kan skrive dem og netværket kan overføre dem. Den påvirkes ikke meget af latens og indsætter muligvis tusindvis af rækker pr. sekund på det samme netværkslink.

Udgifter pr. opgørelse i PostgreSQL

Der er også omkostninger til at parse, planlægge og udføre en erklæring i PostgreSQL. Det skal tage låse, åbne relationsfiler, slå indeks op osv. COPY forsøger at gøre alt dette én gang, i starten, og derefter fokusere på at indlæse rækker så hurtigt som muligt.

Omkostninger til skift af opgaver/kontekst

Der betales yderligere tidsomkostninger på grund af, at styresystemet skal skifte mellem postgres, der venter på en række, mens din app forbereder og sender den, og så venter din app på postgres' svar, mens postgres behandler rækken. Hver gang du skifter fra den ene til den anden, spilder du lidt tid. Mere tid er potentielt spildt på at suspendere og genoptage forskellige lavniveau-kernetilstande, når processer går ind og forlader ventetilstande.

Glip af COPY-optimeringer

Oven i alt det, COPY har nogle optimeringer, den kan bruge til nogle slags belastninger. Hvis der ikke er nogen genereret nøgle, og eventuelle standardværdier er konstanter for eksempel, kan den forudberegne dem og omgå eksekveren fuldstændigt, hurtigt indlæse data i tabellen på et lavere niveau, der springer en del af PostgreSQL's normale arbejde helt over. Hvis du CREATE TABLE eller TRUNCATE i den samme transaktion COPY , kan den gøre endnu flere tricks til at gøre indlæsningen hurtigere ved at omgå den normale transaktionsbogføring, der er nødvendig i en multiklientdatabase.

På trods af dette, PostgreSQL's COPY kunne stadig gøre meget mere for at fremskynde tingene, ting som den endnu ikke ved hvordan man gør. Det kan automatisk springe indeksopdateringer over og derefter genopbygge indekser, hvis du ændrer mere end en bestemt del af tabellen. Det kunne lave indeksopdateringer i batches. Meget mere.

Forpligte omkostninger

En sidste ting at overveje er at forpligte omkostninger. Det er sandsynligvis ikke et problem for dig, fordi psycopg2 standard til at åbne en transaktion og ikke forpligte sig, før du fortæller det. Medmindre du har bedt den bruge autocommit. Men for mange DB-drivere er autocommit standarden. I sådanne tilfælde ville du foretage en commit for hver INSERT . Det betyder én diskflush, hvor serveren sørger for, at den skriver alle data i hukommelsen ud på disken og fortæller diskene, at de skal skrive deres egne caches ud til vedvarende lagring. Dette kan tage lang tid tid, og varierer meget afhængigt af hardwaren. Min SSD-baserede NVMe BTRFS bærbare computer kan kun udføre 200 fsyncs/sekund, mod 300.000 ikke-synkroniserede skrivninger/sekund. Så det vil kun indlæse 200 rækker/sekund! Nogle servere kan kun udføre 50 fsyncs/sekund. Nogle kan klare 20.000. Så hvis du skal commit regelmæssigt, så prøv at indlæse og commit i batches, lav multi-row inserts osv. Fordi COPY kun én commit til sidst, commit omkostninger er ubetydelige. Men dette betyder også COPY kan ikke komme sig efter fejl halvvejs gennem dataene; det fortryder hele bulklasten.



  1. Hvordan kan jeg konvertere flueben til et datoformat?

  2. MySQL:Hvordan nulstilles eller ændres MySQL root-adgangskoden?

  3. Sådan udpakkes en understreng i MySQL

  4. tilpasse pager i psql