{"id":79893,"date":"2020-05-01T13:43:12","date_gmt":"2020-05-01T11:43:12","guid":{"rendered":"https:\/\/prohoster.info\/blog\/administrirovanie\/postgresql-i-jdbc-vyzhimaem-vse-soki-vladimir-sitnikov"},"modified":"2020-05-01T13:43:12","modified_gmt":"2020-05-01T11:43:12","slug":"postgresql-i-jdbc-vyzhimaem-vse-soki-vladimir-sitnikov","status":"publish","type":"post","link":"https:\/\/prohoster.info\/da\/blog\/administrirovanie\/postgresql-i-jdbc-vyzhimaem-vse-soki-vladimir-sitnikov","title":{"rendered":"PostgreSQL og JDBC, vi klemmer alt ud af det. Vladimir Sitnikov","gt_translate_keys":[{"key":"rendered","format":"text"}]},"content":{"rendered":"<p><strong>Jeg tilbyder at g\u00f8re dig bekendt med transskriptionen af Vladimir Sitnikovs rapport fra starten af 2016 \"PostgreSQL og JDBC - vi presser al saft ud\"<\/strong><\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"PostgreSQL og JDBC, vi klemmer alt ud af det. Vladimir Sitnikov\" src=\"\/wp-content\/uploads\/2020\/05\/9d94c8a024bd2821e431c525aae0127d.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><noindex><a rel=\"nofollow\" name=\"habracut\"><\/a><\/noindex><\/p>\n<p><img decoding=\"async\" alt=\"PostgreSQL og JDBC, vi klemmer alt ud af det. Vladimir Sitnikov\" src=\"\/wp-content\/uploads\/2020\/05\/030666abda53aa388b1cb1d0c46a7524.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>Goddag! Mit navn er Vladimir Sitnikov. Jeg har arbejdet i 10 \u00e5r hos NetCracker. Og jeg besk\u00e6ftiger mig prim\u00e6rt med ydeevne. Alt relateret til Java, alt relateret til SQL \u2013 det er det, jeg elsker. <\/p>\n<p><\/p>\n<p>Og i dag vil jeg fort\u00e6lle om de udfordringer, vi st\u00f8dte p\u00e5 i virksomheden, da vi begyndte at bruge PostgreSQL som database-server. Og vi arbejder prim\u00e6rt med Java. Men det, jeg vil tale om i dag, relaterer sig ikke kun til Java. Som erfaringen har vist, opst\u00e5r det ogs\u00e5 i andre sprog. <\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"PostgreSQL og JDBC, vi klemmer alt ud af det. Vladimir Sitnikov\" src=\"\/wp-content\/uploads\/2020\/05\/b01a214d782c7e32797a6c6466457979.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>Vi vil tale om:<\/p>\n<p><\/p>\n<ul>\n<li>dataudtr\u00e6k. <\/li>\n<li>Databearbejdning. <\/li>\n<li>Og ogs\u00e5 om ydeevne. <\/li>\n<li>Og om de faldgruber, der ligger skjult. <\/li>\n<\/ul>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"PostgreSQL og JDBC, vi klemmer alt ud af det. Vladimir Sitnikov\" src=\"\/wp-content\/uploads\/2020\/05\/57da0c6aa4bb62e1beb77160f5aee7e7.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>Lad os starte med et simpelt sp\u00f8rgsm\u00e5l. Vi henter en r\u00e6kke fra tabellen efter det prim\u00e6re n\u00f8gle. <\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"PostgreSQL og JDBC, vi klemmer alt ud af det. Vladimir Sitnikov\" src=\"\/wp-content\/uploads\/2020\/05\/d5fcb1172aef402a87064498bf8a5218.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>Databasen ligger p\u00e5 samme v\u00e6rt. Og hele dette system tager 20 millisekunder.<\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"PostgreSQL og JDBC, vi klemmer alt ud af det. Vladimir Sitnikov\" src=\"\/wp-content\/uploads\/2020\/05\/103b7f9736b82a3313491b2f0d2a5824.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>De 20 millisekunder er meget. Hvis du har 100 s\u00e5danne foresp\u00f8rgsler, bruger du tid i sekunder p\u00e5 at behandle disse foresp\u00f8rgsler, det vil sige spilder tid.<\/p>\n<p><\/p>\n<p>Vi kan ikke lide at g\u00f8re det og kigger p\u00e5, hvad databasen tilbyder os til dette. Databasen tilbyder os to muligheder for at udf\u00f8re foresp\u00f8rgsler. <\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"PostgreSQL og JDBC, vi klemmer alt ud af det. Vladimir Sitnikov\" src=\"\/wp-content\/uploads\/2020\/05\/b467e86a0f8c4c32cea182fe27a28e6e.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>Den f\u00f8rste mulighed er en simpel foresp\u00f8rgsel. Hvad er fordelen ved den? Den er god, fordi vi blot tager den og sender den uden mere. <\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"PostgreSQL og JDBC, vi klemmer alt ud af det. Vladimir Sitnikov\" src=\"\/wp-content\/uploads\/2020\/05\/7e333a62ba68feb0781ff96e39486591.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p><noindex><a rel=\"nofollow\" href=\"https:\/\/github.com\/pgjdbc\/pgjdbc\/pull\/478\">https:\/\/github.com\/pgjdbc\/pgjdbc\/pull\/478<\/a><\/noindex><\/p>\n<p><\/p>\n<p>Databasen har ogs\u00e5 en udvidet foresp\u00f8rgsel, som er mere us\u00e6dvanlig, men mere funktionel. Man kan sende foresp\u00f8rgsler om parsing, udf\u00f8relse, variabelbinding osv. separat. <\/p>\n<p><\/p>\n<p>Super udvidet foresp\u00f8rgsel \u2013 det vil vi ikke d\u00e6kke i den nuv\u00e6rende rapport. M\u00e5ske \u00f8nsker vi noget fra databasen, og der er en liste over \u00f8nsker, som er blevet dannet p\u00e5 en eller anden m\u00e5de, det vil sige, det er det, vi \u00f8nsker, men det er umuligt lige nu og inden for det n\u00e6ste \u00e5r. Derfor skriver vi det ned og vil g\u00e5 hen og ryste de vigtigste folk.<\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"PostgreSQL og JDBC, vi klemmer alt ud af det. Vladimir Sitnikov\" src=\"\/wp-content\/uploads\/2020\/05\/19094729074fd28c5b9f236833a9a266.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>Det, vi kan g\u00f8re, er simpel foresp\u00f8rgsel og udvidet foresp\u00f8rgsel.<\/p>\n<p><\/p>\n<p>Hvad er s\u00e6regenheden ved hver tilgang? <\/p>\n<p><\/p>\n<p>Simpel foresp\u00f8rgsel er godt at bruge til engangsudf\u00f8relse. Udf\u00f8r den \u00e9n gang og glem den. Problemet er, at den ikke underst\u00f8tter bin\u00e6rt dataformat, det vil sige for nogle h\u00f8jtydende systemer er den ikke egnet.<\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"PostgreSQL og JDBC, vi klemmer alt ud af det. Vladimir Sitnikov\" src=\"\/wp-content\/uploads\/2020\/05\/062c0e45cefd91ece331a306a7651bde.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>Udvidet foresp\u00f8rgsel \u2013 sparer tid p\u00e5 parsing. Det er det, vi har gjort og begyndt at bruge. Det har hjulpet os ekstremt meget. Der er ikke kun besparelse p\u00e5 parsing. Der er ogs\u00e5 besparelse p\u00e5 dataoverf\u00f8rsel. At overf\u00f8re data i bin\u00e6rt format er meget mere effektivt. <\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"PostgreSQL og JDBC, vi klemmer alt ud af det. Vladimir Sitnikov\" src=\"\/wp-content\/uploads\/2020\/05\/6df83a2f3736568668cf9d74de5d9758.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>Lad os g\u00e5 til praksis. S\u00e5dan ser en typisk applikation ud. Dette kan v\u00e6re Java osv. <\/p>\n<p><\/p>\n<p>Vi har oprettet en statement. Udf\u00f8rt kommandoen. Oprettet en close. Hvor er fejlen her? Hvad er problemet? Der er ingen problemer. S\u00e5dan st\u00e5r der i alle b\u00f8ger. S\u00e5dan skal man skrive. Hvis du \u00f8nsker maksimal ydeevne, s\u00e5 skriv s\u00e5ledes. <\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"PostgreSQL og JDBC, vi klemmer alt ud af det. Vladimir Sitnikov\" src=\"\/wp-content\/uploads\/2020\/05\/6923293946dec45b3fd508235728ab95.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>Men praksis har vist, at dette ikke virker. Hvorfor? Fordi vi har metoden \u00abclose\u00bb. Og n\u00e5r vi g\u00f8r s\u00e5dan, s\u00e5 er det fra databasens synspunkt \u2013 det svarer til en ryger, der arbejder med databasen. Vi sagde \u00abPARSE EXECUTE DEALLOCATE\u00bb.<\/p>\n<p><\/p>\n<p>Hvorfor disse un\u00f8dvendige oprettelser og eksport af statements? De er ikke n\u00f8dvendige for nogen. Men normalt i PreparedStatement sker det, at n\u00e5r vi lukker dem, lukker de alt i databasen. Det er ikke det, vi \u00f8nsker. <\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"PostgreSQL og JDBC, vi klemmer alt ud af det. Vladimir Sitnikov\" src=\"\/wp-content\/uploads\/2020\/05\/5a357a209e414024c437d042f600f251.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>Vi \u00f8nsker, ligesom sunde mennesker, at arbejde med databasen. En gang tog vi og forberedte vores statement, og s\u00e5 udf\u00f8rer vi det mange gange. I virkeligheden mange gange \u2013 det er en gang i hele applikationens liv, vi har parseret. Og p\u00e5 forskellige REST bruger vi det samme statement id. Det er vores m\u00e5l. <\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"PostgreSQL og JDBC, vi klemmer alt ud af det. Vladimir Sitnikov\" src=\"\/wp-content\/uploads\/2020\/05\/ac4aed702a624ad9f9addc4362daf760.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>Hvordan kan vi n\u00e5 dette? <\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"PostgreSQL og JDBC, vi klemmer alt ud af det. Vladimir Sitnikov\" src=\"\/wp-content\/uploads\/2020\/05\/0f101d890d1a2af8e99f8a3a8a06fd5a.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>Meget simpelt \u2013 vi skal ikke lukke statements. Vi skriver s\u00e5dan: \u00abprepare\u00bb \u00abexecute\u00bb. <\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"PostgreSQL og JDBC, vi klemmer alt ud af det. Vladimir Sitnikov\" src=\"\/wp-content\/uploads\/2020\/05\/0b3fd8fd4f5861d4a76cad5a8421ddad.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"PostgreSQL og JDBC, vi klemmer alt ud af det. Vladimir Sitnikov\" src=\"\/wp-content\/uploads\/2020\/05\/724646bfc55b5e2b611b1584ca8ba6aa.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>Hvis vi k\u00f8rer s\u00e5dan noget, s\u00e5 er det klart, at et eller andet sted overfyldes. Hvis det ikke er klart, kan vi m\u00e5le. Lad os tage og skrive en benchmark, hvor vi har en s\u00e5 simpel metode. Vi opretter en statement. K\u00f8rer p\u00e5 en eller anden version af driveren og f\u00e5r, at den falder ret hurtigt med tab af al hukommelse, som vi har mistet. <\/p>\n<p><\/p>\n<p>Det er klart, at s\u00e5danne fejl let kan rettes. Jeg vil ikke tale om dem. Men jeg vil sige, at i den nye version fungerer det meget hurtigere. Metoden er meningsl\u00f8s, men ikke desto mindre. <\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"PostgreSQL og JDBC, vi klemmer alt ud af det. Vladimir Sitnikov\" src=\"\/wp-content\/uploads\/2020\/05\/b232a6205e708c70f52be0024bbe9980.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>Hvordan arbejder man korrekt? Hvad skal vi g\u00f8re for dette?<\/p>\n<p><\/p>\n<p>I virkeligheden lukker applikationerne altid statements. I alle b\u00f8ger skriver de, at man skal lukke dem, ellers l\u00e6kker hukommelse. <\/p>\n<p><\/p>\n<p>Og PostgreSQL kan ikke cache foresp\u00f8rgsler. Hver session skal selv oprette denne cache. <\/p>\n<p><\/p>\n<p>Og vi vil heller ikke bruge tid p\u00e5 parsing. <\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"PostgreSQL og JDBC, vi klemmer alt ud af det. Vladimir Sitnikov\" src=\"\/wp-content\/uploads\/2020\/05\/85b9574938aa6e6bf59c956e3728bdc3.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>Og som s\u00e6dvanlig har vi to muligheder. <\/p>\n<p><\/p>\n<p>Den f\u00f8rste mulighed er, at vi tager og siger, lad os pakke alt ind i PgSQL. Der er caching. Det cachen alt. Det vil blive fantastisk. Vi har kigget p\u00e5 det. Vi har 100500 foresp\u00f8rgsler. Det virker ikke. Vi er ikke enige \u2013 vi vil ikke h\u00e5ndtere foresp\u00f8rgsler manuelt. Nej-nej. <\/p>\n<p><\/p>\n<p>Vi har en anden mulighed \u2013 at tage og lave det selv. Vi \u00e5bner kildefilerne og begynder at kode. Koder, koder. Det viste sig, at det ikke er s\u00e5 sv\u00e6rt at g\u00f8re. <\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"PostgreSQL og JDBC, vi klemmer alt ud af det. Vladimir Sitnikov\" src=\"\/wp-content\/uploads\/2020\/05\/501620b014800406167d20668baef709.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p><noindex><a rel=\"nofollow\" href=\"https:\/\/github.com\/pgjdbc\/pgjdbc\/pull\/319\">https:\/\/github.com\/pgjdbc\/pgjdbc\/pull\/319<\/a><\/noindex><\/p>\n<p><\/p>\n<p>Dette kom frem i august 2015. Der er nu en mere moderne version. Og alt g\u00e5r fantastisk. Det fungerer s\u00e5 godt, at vi ikke \u00e6ndrer noget i applikationen. Og vi er endda holdt op med at t\u00e6nke i retning af PgSQL, dvs. det var nok til at reducere alle omkostninger til n\u00e6sten nul. <\/p>\n<p><\/p>\n<p>Server-prepared statements aktiveres ved den femte udf\u00f8relse for at undg\u00e5 at bruge hukommelse i databasen til hver enkelt engangsforesp\u00f8rgsel. <\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"PostgreSQL og JDBC, vi klemmer alt ud af det. Vladimir Sitnikov\" src=\"\/wp-content\/uploads\/2020\/05\/8ee95e71f92187941989ad0c18ece0c0.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>Man kan sp\u00f8rge \u2013 hvor er tallene? Hvad f\u00e5r I? Og her kan jeg ikke give tal, fordi det er forskellige for hver foresp\u00f8rgsel.<\/p>\n<p><\/p>\n<p>Vores foresp\u00f8rgsler var s\u00e5dan, at vi brugte omkring 20 millisekunder p\u00e5 parsing af OLTP-foresp\u00f8rgsler. Det var 0,5 millisekunder til udf\u00f8relse, 20 millisekunder til parsing. Foresp\u00f8rgsel \u2013 10 KiB tekst, 170 linjer plan. Dette er en OLTP-foresp\u00f8rgsel. Den anmoder om 1, 5, 10 linjer, nogle gange mere. <\/p>\n<p><\/p>\n<p>Men vi \u00f8nskede slet ikke at bruge 20 millisekunder. Vi reducerede det til 0. Alt er godt. <\/p>\n<p><\/p>\n<p>Hvad kan I tage med herfra? Hvis I bruger Java, s\u00e5 tager I den moderne version af driveren og er glade. <\/p>\n<p><\/p>\n<p>Hvis I bruger et andet sprog, s\u00e5 t\u00e6nk \u2013 m\u00e5ske underminerer dette ogs\u00e5 jer? For set fra det endelige sprog, for eksempel, hvis PL 8 eller LibPQ, s\u00e5 er det ikke indlysende, at I bruger tid ikke p\u00e5 udf\u00f8relsen, men p\u00e5 parsing, og det er v\u00e6rd at tjekke. Hvordan? Alt er gratis. <\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"PostgreSQL og JDBC, vi klemmer alt ud af det. Vladimir Sitnikov\" src=\"\/wp-content\/uploads\/2020\/05\/fda6b1c1b126cb85c970e42335e1dc24.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>Undtagen at der er fejl og nogle s\u00e6rlige forhold. Og dem vil vi netop tale om nu. St\u00f8rstedelen vil handle om industriel ark\u00e6ologi, om hvad vi har fundet, og hvad vi er st\u00f8dt p\u00e5. <\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"PostgreSQL og JDBC, vi klemmer alt ud af det. Vladimir Sitnikov\" src=\"\/wp-content\/uploads\/2020\/05\/9a3b383f83c5e227cd02952c5825b64f.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>Hvis foresp\u00f8rgslen genereres dynamisk. Det sker nogle gange. Nogen klipper strenge sammen, og det bliver en SQL-foresp\u00f8rgsel.<\/p>\n<p><\/p>\n<p>Hvad er galt med det? Det er d\u00e5rligt, fordi vi hver gang ender med en anden streng.<\/p>\n<p><\/p>\n<p>Og denne forskellige r\u00e6kke skal beregne hashCode igen. Det er virkelig en CPU-opgave \u2013 at finde den lange foresp\u00f8rgsel i selv en eksisterende hash er ikke s\u00e5 let. S\u00e5 konklusionen er simpel \u2013 generer ikke foresp\u00f8rgsler. Opbevar dem i en enkelt variabel. Og v\u00e6r glad.<\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"PostgreSQL og JDBC, vi klemmer alt ud af det. Vladimir Sitnikov\" src=\"\/wp-content\/uploads\/2020\/05\/bcd4f729204cecdb572a98f357bcc33f.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>N\u00e6ste problem. Datatyper er vigtige. Der findes ORM'er, der siger, at det ikke er vigtigt, hvilken NULL det er, lad det v\u00e6re en eller anden. Hvis det er Int, s\u00e5 siger vi setInt. Og hvis det er NULL, s\u00e5 lad det altid v\u00e6re VARCHAR. Og hvad g\u00f8r det i sidste ende, hvilken NULL der er der? Databasen forst\u00e5r det selv. Og s\u00e5dan et billede fungerer ikke. <\/p>\n<p><\/p>\n<p>I praksis er databasen slet ikke ligeglad. <strong>Hvis du f\u00f8rste gang sagde, at dette er et tal, og anden gang sagde, at det er VARCHAR, s\u00e5 er det umuligt at genbruge server-forberedte statements. Og i s\u00e5 fald m\u00e5 vi genskabe vores statement fra bunden.<\/strong><\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"PostgreSQL og JDBC, vi klemmer alt ud af det. Vladimir Sitnikov\" src=\"\/wp-content\/uploads\/2020\/05\/552d9c2e25cf9abbdfef12c98d027740.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>Hvis du udf\u00f8rer den samme foresp\u00f8rgsel, s\u00e5 s\u00f8rg for, at datatyperne i kolonnen ikke blandes. Du skal holde \u00f8je med NULL. Dette er en almindelig fejl, vi havde, efter vi begyndte at bruge PreparedStatements.<\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"PostgreSQL og JDBC, vi klemmer alt ud af det. Vladimir Sitnikov\" src=\"\/wp-content\/uploads\/2020\/05\/5d73c8f5dfa281c3bda962fc3e5edd84.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>Okay, vi har aktiveret det. M\u00e5ske brugte vi en driver. Og ydeevnen faldt. Alt blev d\u00e5rligt. <\/p>\n<p><\/p>\n<p>Hvordan kan det ske? Er det en bug eller en funktion? Desv\u00e6rre kunne vi ikke forst\u00e5 \u2013 om det var en bug eller en funktion. Men der er et ret enkelt reproduktionsscenarie for dette problem. Det overraskede os helt. Og det handler om at hente data fra bogstaveligt talt \u00e9n tabel. Vi havde selvf\u00f8lgelig flere af s\u00e5danne foresp\u00f8rgsler. De involverede normalt to-tre tabeller, men der er dette reproduktionsscenarie. Tag en hvilken som helst version af din database og reproducer det.<\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"PostgreSQL og JDBC, vi klemmer alt ud af det. Vladimir Sitnikov\" src=\"\/wp-content\/uploads\/2020\/05\/fa0fdd037c2eaa31667d5a527bb71f9c.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p><noindex><a rel=\"nofollow\" href=\"https:\/\/gist.github.com\/vlsi\/df08cbef370b2e86a5c1\">https:\/\/gist.github.com\/vlsi\/df08cbef370b2e86a5c1<\/a><\/noindex><\/p>\n<p><\/p>\n<p>Essensen er, at vi har to kolonner, hver af dem indekseret. I den ene kolonne er der en million r\u00e6kker med NULL-v\u00e6rdier. Og i den anden kolonne er der kun 20 r\u00e6kker. N\u00e5r vi udf\u00f8rer uden sammenkoblede variable, fungerer alt fint. <\/p>\n<p><\/p>\n<p>Hvis vi begynder at udf\u00f8re med sammenkoblede variable, dvs. n\u00e5r vi bruger tegn \u00ab?\u00bb eller \u00ab$1\u00bb til vores foresp\u00f8rgsel, hvad f\u00e5r vi s\u00e5 i sidste ende?<\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"PostgreSQL og JDBC, vi klemmer alt ud af det. Vladimir Sitnikov\" src=\"\/wp-content\/uploads\/2020\/05\/e91c397796c7ddcbade3bc090719e9d1.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p><noindex><a rel=\"nofollow\" href=\"https:\/\/gist.github.com\/vlsi\/df08cbef370b2e86a5c1\">https:\/\/gist.github.com\/vlsi\/df08cbef370b2e86a5c1<\/a><\/noindex><\/p>\n<p><\/p>\n<p>Den f\u00f8rste udf\u00f8relse \u2013 som det skal v\u00e6re. Den anden \u2013 lidt hurtigere. Noget blev cachet. Den tredje-fjerde-femte. S\u00e5 bang \u2013 og s\u00e5dan. Og det v\u00e6rste er, at det sker ved den sjette udf\u00f8relse. Hvem vidste, at man skulle lave pr\u00e6cis seks udf\u00f8relser for at finde ud af, hvad den egentlige eksekveringsplan var?<\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"PostgreSQL og JDBC, vi klemmer alt ud af det. Vladimir Sitnikov\" src=\"\/wp-content\/uploads\/2020\/05\/893c955bc1e2e15a6986690e516f72a9.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>Hvem er skyld i det? Hvad skete der? Databasen indeholder en optimering. Og den er tilsyneladende optimeret til et generisk tilf\u00e6lde. Og derfor, fra et bestemt punkt, overg\u00e5r den til en generisk plan, som desv\u00e6rre kan vise sig at v\u00e6re en anden. Den kan enten v\u00e6re den samme eller en anden. Og der er en t\u00e6rskelv\u00e6rdi, der f\u00f8rer til en s\u00e5dan adf\u00e6rd. <\/p>\n<p><\/p>\n<p>Hvad kan der g\u00f8res ved dette? Her er det selvf\u00f8lgelig mere komplekst at spekulere. Der er en simpel l\u00f8sning, som vi bruger. Det er +0, OFFSET 0. I er garanteret bekendt med s\u00e5danne l\u00f8sninger. Vi tager bare og tilf\u00f8jer \u00ab+0\u00bb i foresp\u00f8rgslen, og s\u00e5 er alt godt. Jeg vil vise det senere. <\/p>\n<p><\/p>\n<p>Og der er ogs\u00e5 en anden mulighed \u2013 at se n\u00e6rmere p\u00e5 planerne. Udvikleren skal ikke kun skrive foresp\u00f8rgslen, men ogs\u00e5 sige \u00abexplain analyze\u00bb 6 gange. Hvis det er 5, s\u00e5 er det ikke tilstr\u00e6kkeligt. <\/p>\n<p><\/p>\n<p>Og der er ogs\u00e5 en tredje mulighed \u2013 at skrive et brev til pgsql-hackers. Jeg har skrevet, men indtil videre er det ikke klart, om det er en fejl eller en funktion.<\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"PostgreSQL og JDBC, vi klemmer alt ud af det. Vladimir Sitnikov\" src=\"\/wp-content\/uploads\/2020\/05\/8dc8d3a78e0b794e1ceba20f6ca914ae.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p><noindex><a rel=\"nofollow\" href=\"https:\/\/gist.github.com\/vlsi\/df08cbef370b2e86a5c1\">https:\/\/gist.github.com\/vlsi\/df08cbef370b2e86a5c1<\/a><\/noindex><\/p>\n<p><\/p>\n<p>Mens vi t\u00e6nker over, om det er en fejl eller en funktion, lad os rette det. Vi tager vores foresp\u00f8rgsel og tilf\u00f8jer \u00ab+0\u00bb. Alt er godt. To tegn, og vi skal ikke engang t\u00e6nke over, hvordan det er. Meget enkelt. Vi har bare forbudt databasen at bruge indekset for denne kolonne. Vi har ikke noget indeks p\u00e5 kolonnen \u00ab+0\u00bb, og derfor bruger databasen ikke indekset, det hele er i orden. <\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"PostgreSQL og JDBC, vi klemmer alt ud af det. Vladimir Sitnikov\" src=\"\/wp-content\/uploads\/2020\/05\/5261d80d084786a15b9764f6367014cd.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>Dette er reglen om 6 explain-ordrer. I de nuv\u00e6rende versioner skal man g\u00f8re det 6 gange, hvis man har relaterede variabler. Hvis man ikke har relaterede variabler, s\u00e5 g\u00f8r vi det p\u00e5 denne m\u00e5de. Og i sidste ende falder netop denne foresp\u00f8rgsel. Det er ikke kompliceret.<\/p>\n<p><\/p>\n<p>Det kunne man mene, hvor l\u00e6nge kan det tage? Her er en fejl, der er en fejl der. Virkelig, der er fejl overalt. <\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"PostgreSQL og JDBC, vi klemmer alt ud af det. Vladimir Sitnikov\" src=\"\/wp-content\/uploads\/2020\/05\/674dc7e7b4624baa5c79eee9e1e89db0.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>Lad os se n\u00e6rmere p\u00e5 det. For eksempel har vi to skemaer. Skema A med tabel Y og skema B med tabel Y. Foresp\u00f8rgslen \u2013 at v\u00e6lge data fra tabellen. Hvad vil der ske? Vi vil have en fejl. Vi vil have alt det ovenst\u00e5ende. Reglen er s\u00e5dan \u2013 fejl overalt, vi vil have alt det n\u00e6vnte.<\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"PostgreSQL og JDBC, vi klemmer alt ud af det. Vladimir Sitnikov\" src=\"\/wp-content\/uploads\/2020\/05\/dd6f544bb9e930c39e36523c9afe6003.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>Nu et sp\u00f8rgsm\u00e5l: \u00abHvorfor?\u00bb. Det kunne synes, at der er dokumentation, der siger, at hvis vi har et skema, er der en variabel \u00absearch_path\u00bb, der angiver, hvor tabellen skal s\u00f8ges. Det kunne synes, at variablen er der.<\/p>\n<p><\/p>\n<p>Hvad er problemet? Problemet er, at server-forberedte udsagn ikke har mistanke om, at s\u00f8gebanen kan \u00e6ndres af nogen. Denne v\u00e6rdi forbliver som en konstant for databasen. Og nogle dele kan miste de nye v\u00e6rdier. <\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"PostgreSQL og JDBC, vi klemmer alt ud af det. Vladimir Sitnikov\" src=\"\/wp-content\/uploads\/2020\/05\/f738301606d84d72bfa7cc5b568c0df8.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>Selvf\u00f8lgelig afh\u00e6nger det af den version, du tester. Det afh\u00e6nger af, hvor meget dine tabeller adskiller sig. Og version 9.1 vil blot udf\u00f8re de gamle foresp\u00f8rgsler. Nyere versioner kan opdage en fejl og sige, at der er en fejl.<\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"PostgreSQL og JDBC, vi klemmer alt ud af det. Vladimir Sitnikov\" src=\"\/wp-content\/uploads\/2020\/05\/4761cd92835b94acbf9d6c9d21817316.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p><noindex><a rel=\"nofollow\" href=\"https:\/\/www.postgresql.org\/message-id\/CAB=Je-GQOW7kU9Hn3AqP1vhaZg_wE9Lz6F4jSp-7cm9_M6DyVA@mail.gmail.com\">Set search_path + server-forberedte udsagn =<br \/>\nden cachede plan m\u00e5 ikke \u00e6ndre resultattypen<\/a><\/noindex><\/p>\n<p><\/p>\n<p>Hvordan l\u00f8ser man dette? Der er en simpel opskrift \u2013 g\u00f8r ikke s\u00e5dan. Du b\u00f8r ikke \u00e6ndre search_path under appens drift. Hvis du \u00e6ndrer det, er det bedre at oprette en ny forbindelse.<\/p>\n<p><\/p>\n<p>Vi kan diskutere det, dvs. \u00e5bne det, diskutere det, tilf\u00f8je til det. M\u00e5ske kan vi overbevise databaseudviklerne om, at n\u00e5r nogen \u00e6ndrer en v\u00e6rdi, skal databasen informere kunden: \"Se, din v\u00e6rdi er blevet opdateret. M\u00e5ske skal du nulstille eller genskabe udsagnene?\" I \u00f8jeblikket opf\u00f8rer databasen sig skjult og informerer ikke om, at udsagnene er \u00e6ndret indeni. <\/p>\n<p><\/p>\n<p>Og jeg vil igen understrege \u2013 dette er ikke typisk for Java. Vi vil se det samme i PL\/pgSQL et til et. Men der vil det blive reproduceret.<\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"PostgreSQL og JDBC, vi klemmer alt ud af det. Vladimir Sitnikov\" src=\"\/wp-content\/uploads\/2020\/05\/a4e7b201d0c0aa4a0092d2b6ff152df7.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>Lad os pr\u00f8ve at v\u00e6lge data igen. Vi v\u00e6lger og v\u00e6lger. Vi har en tabel med en million r\u00e6kker. Hver r\u00e6kke er p\u00e5 en kilobyte. Cirka en gigabyte data. Og vi har en arbejdshukommelse i Java-maskinen p\u00e5 128 megabyte. <\/p>\n<p><\/p>\n<p>Som anbefalet i alle b\u00f8ger, bruger vi streamingbehandling. Dvs. vi \u00e5bner resultSet og l\u00e6ser derfra data lidt ad gangen. Vil det fungere? Vil der v\u00e6re nedbrud p\u00e5 grund af hukommelse? Vil vi l\u00e6se lidt ad gangen? Lad os stole p\u00e5 databasen, lad os stole p\u00e5 Postgres. Vi stoler ikke. Vil vi f\u00e5 OutOfMemory? Hvem har oplevet OutOfMemory? Hvem har v\u00e6ret i stand til at reparere det efterf\u00f8lgende? <\/p>\n<p><\/p>\n<p>Hvis du har en million r\u00e6kker, kan du ikke bare v\u00e6lge. Du skal absolut bruge OFFSET\/LIMIT. Hvem er for denne mulighed? Og hvem er for at lege med autoCommit? <\/p>\n<p><\/p>\n<p>Her viser det sig, som s\u00e6dvanligt, at den mest uventede mulighed er den rigtige. Og hvis du slukker for autoCommit, vil det hj\u00e6lpe. Hvorfor? Videnskaben ved ikke noget om det. <\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"PostgreSQL og JDBC, vi klemmer alt ud af det. Vladimir Sitnikov\" src=\"\/wp-content\/uploads\/2020\/05\/2e5d9d2a8450a9069155de86a8ec387a.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>Men som standard v\u00e6lger alle klienter, der forbinder til Postgres-databasen, data i sin helhed. PgJDBC er ikke en undtagelse i denne henseende, den v\u00e6lger alle r\u00e6kker.<\/p>\n<p><\/p>\n<p>Der er en variation af FetchSize, dvs. du kan p\u00e5 niveauet for et enkelt udsagn sige, at du gerne vil v\u00e6lge data i portioner af 10, 50. Men det fungerer ikke, f\u00f8r du slukker for autoCommit. N\u00e5r du slukker for autoCommit, begynder det at fungere. <\/p>\n<p><\/p>\n<p>Men at g\u00e5 igennem koden og s\u00e6tte setFetchSize overalt \u2013 det er ikke praktisk. Derfor har vi lavet en indstilling, som angiver standardv\u00e6rdien for hele forbindelsen.<\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"PostgreSQL og JDBC, vi klemmer alt ud af det. Vladimir Sitnikov\" src=\"\/wp-content\/uploads\/2020\/05\/c9ac8e483dc6bfdbbc300972ee1ab1e0.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>Her har vi sagt det. Vi har indstillet parameteren. Og hvad er resultatet? Hvis vi v\u00e6lger lidt, f.eks. 10 r\u00e6kker, s\u00e5 er der ganske store overhead omkostninger. Derfor skal denne v\u00e6rdi s\u00e6ttes til cirka hundrede. <\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"PostgreSQL og JDBC, vi klemmer alt ud af det. Vladimir Sitnikov\" src=\"\/wp-content\/uploads\/2020\/05\/073e7a4af63688396eefe332ba8261d6.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>Ideelt set skulle man selvf\u00f8lgelig ogs\u00e5 l\u00e6re at begr\u00e6nse i bytes, men opskriften er s\u00e5dan: s\u00e6t defaultRowFetchSize over hundrede og v\u00e6r tilfreds. <\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"PostgreSQL og JDBC, vi klemmer alt ud af det. Vladimir Sitnikov\" src=\"\/wp-content\/uploads\/2020\/05\/e3078faf2078fcaec10d6d99872a9990.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>Lad os g\u00e5 videre til inds\u00e6ttelse af data. Inds\u00e6ttelse er lettere, der er forskellige muligheder. For eksempel, INSERT, VALUES. Det er en god mulighed. Man kan ogs\u00e5 sige \"INSERT SELECT\". I praksis er det det samme. Der er ingen forskel i ydeevnen. <\/p>\n<p><\/p>\n<p>B\u00f8ger siger, at vi skal udf\u00f8re batch statements, b\u00f8ger siger, at man kan udf\u00f8re mere komplekse kommandoer med flere parenteser. Og i Postgres er der en fantastisk funktion \u2013 man kan g\u00f8re COPY, dvs. g\u00f8re det hurtigere. <\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"PostgreSQL og JDBC, vi klemmer alt ud af det. Vladimir Sitnikov\" src=\"\/wp-content\/uploads\/2020\/05\/4d281c9515bdf8de7fbf1e9922d192d0.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>Hvis man m\u00e5ler, kan man igen lave flere interessante opdagelser. Hvordan vil vi have, at det fungerer? Vi \u00f8nsker ikke at parse og udf\u00f8re un\u00f8dvendige kommandoer. <\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"PostgreSQL og JDBC, vi klemmer alt ud af det. Vladimir Sitnikov\" src=\"\/wp-content\/uploads\/2020\/05\/7b2e4343c51dab3ddb6919bf0f117c4d.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>I praksis tillader TCP os ikke at g\u00f8re s\u00e5dan. Hvis klienten er optaget af at sende en anmodning, l\u00e6ser databasen ikke anmodningerne i sine fors\u00f8g p\u00e5 at sende os svarene. Til sidst venter klienten p\u00e5 databasen, indtil den l\u00e6ser anmodningen, og databasen venter p\u00e5 klienten, indtil han l\u00e6ser svaret. <\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"PostgreSQL og JDBC, vi klemmer alt ud af det. Vladimir Sitnikov\" src=\"\/wp-content\/uploads\/2020\/05\/17a062c30ddd83cb890775ec1722044f.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>Og derfor er klienten n\u00f8dt til at sende et synkroniseringspakke periodevis. Un\u00f8dvendige netv\u00e6rk interaktioner, un\u00f8dvendigt tidstab.<\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"PostgreSQL og JDBC, vi klemmer alt ud af det. Vladimir Sitnikov\" src=\"\/wp-content\/uploads\/2020\/05\/ae7a4f32e2949c1d0550da051937de02.jpg\" style=\"display:block;margin: 0 auto;\" \/>Og jo flere vi tilf\u00f8jer, desto v\u00e6rre bliver det. Driveren er meget pessimistisk og tilf\u00f8jer dem ret ofte, cirka hver 200. r\u00e6kke, afh\u00e6ngigt af st\u00f8rrelsen p\u00e5 r\u00e6kkerne osv. <\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"PostgreSQL og JDBC, vi klemmer alt ud af det. Vladimir Sitnikov\" src=\"\/wp-content\/uploads\/2020\/05\/82b1d597986633a8c4b7952517ca6477.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p><noindex><a rel=\"nofollow\" href=\"https:\/\/github.com\/pgjdbc\/pgjdbc\/pull\/380\">https:\/\/github.com\/pgjdbc\/pgjdbc\/pull\/380<\/a><\/noindex><\/p>\n<p><\/p>\n<p>Nogle gange kan det v\u00e6re, at du kun retter en enkelt r\u00e6kke, og s\u00e5 accelererer alt ti gange. Det sker. Hvorfor? Som s\u00e6dvanlig er en konstant allerede blevet brugt et sted. Og v\u00e6rdien \"128\" var ment til \u2013 ikke at bruge batching.<\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"PostgreSQL og JDBC, vi klemmer alt ud af det. Vladimir Sitnikov\" src=\"\/wp-content\/uploads\/2020\/05\/7b6bcd95591b36441037b4c4631d2ad0.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p><noindex><a rel=\"nofollow\" href=\"http:\/\/openjdk.java.net\/projects\/code-tools\/jmh\/\">Java microbenchmark harness<\/a><\/noindex><\/p>\n<p><\/p>\n<p>Det er godt, at dette ikke kom med i den officielle version. Vi opdagede det, f\u00f8r vi begyndte at udgive en version. Alle de v\u00e6rdier, jeg n\u00e6vner, er baseret p\u00e5 moderne versioner. <\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"PostgreSQL og JDBC, vi klemmer alt ud af det. Vladimir Sitnikov\" src=\"\/wp-content\/uploads\/2020\/05\/28c82d9e11f6bdaf3cf62b49fc074d68.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>Lad os m\u00e5le. Vi m\u00e5ler InsertBatch simpelt. Vi m\u00e5ler InsertBatch flere gange, dvs. det samme, men med mange values. En smart metode. Ikke alle kan g\u00f8re det, men det er en simpel metode, meget lettere end COPY.<\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"PostgreSQL og JDBC, vi klemmer alt ud af det. Vladimir Sitnikov\" src=\"\/wp-content\/uploads\/2020\/05\/72f7cf6c3b9d9175d3e5a6d5410fe209.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>Man kan g\u00f8re COPY.<\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"PostgreSQL og JDBC, vi klemmer alt ud af det. Vladimir Sitnikov\" src=\"\/wp-content\/uploads\/2020\/05\/2b0d8bbcc50f1293c9a8a1eb8eb70d2e.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>Og man kan g\u00f8re dette med strukturer. Deklar\u00e9r User default type, overf\u00f8r et array og INSERT direkte ind i tabellen. <\/p>\n<p><\/p>\n<p>Hvis du \u00e5bner linket: pgjdbc\/ubenchmsrk\/InsertBatch.java, s\u00e5 er denne kode tilg\u00e6ngelig p\u00e5 GitHub. Du kan se pr\u00e6cist, hvilke foresp\u00f8rgsler der genereres der. Det er ikke s\u00e5 vigtigt.<\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"PostgreSQL og JDBC, vi klemmer alt ud af det. Vladimir Sitnikov\" src=\"\/wp-content\/uploads\/2020\/05\/28dede211fe401286685ca62081453de.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>Vi har k\u00f8rt den. Og det f\u00f8rste, vi inds\u00e5, var, at det er simpelthen umuligt ikke at bruge batch. Alle batching-varianter er lig med nul, dvs. udf\u00f8relsestiden er n\u00e6sten nul sammenlignet med en enkelt udf\u00f8relse. <\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"PostgreSQL og JDBC, vi klemmer alt ud af det. Vladimir Sitnikov\" src=\"\/wp-content\/uploads\/2020\/05\/4ea68f712bbdeadd35f5baa4ddaeff33.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>Vi inds\u00e6tter data. Det er en temmelig simpel tabel. Tre kolonner. Og hvad ser vi her? Vi ser, at alle disse tre varianter er nogenlunde sammenlignelige. Og COPY er selvf\u00f8lgelig bedst.<\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"PostgreSQL og JDBC, vi klemmer alt ud af det. Vladimir Sitnikov\" src=\"\/wp-content\/uploads\/2020\/05\/2686f1d7eea347a839ac23aef2a27e53.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>Det er, n\u00e5r vi inds\u00e6tter data i portioner. N\u00e5r vi sagde, at vi har \u00e9t v\u00e6rdien VALUES, to v\u00e6rdier VALUES, tre v\u00e6rdier VALUES, eller vi n\u00e6vnte dem 10 adskilt af komma. Dette er pr\u00e6cist nu p\u00e5 tv\u00e6rs. 1, 2, 4, 128. Det er tydeligt, at batchinds\u00e6ttelse, som er tegnet med bl\u00e5t, har det meget lettere. Dvs. n\u00e5r du inds\u00e6tter \u00e9n for \u00e9n eller endda n\u00e5r du inds\u00e6tter fire, s\u00e5 bliver det dobbelt s\u00e5 godt, bare fordi vi har fyldt lidt mere ind i VALUES. F\u00e6rre EXECUTE-operationer.<\/p>\n<p><\/p>\n<p>At bruge COPY til sm\u00e5 m\u00e6ngder er ekstremt uheldigt. Jeg tegnede ikke engang de f\u00f8rste to. De g\u00e5r op i himlen, dvs. de gr\u00f8nne tal for COPY.<\/p>\n<p><\/p>\n<p>COPY skal bruges, n\u00e5r dit datas\u00e6t er st\u00f8rre end hundrede r\u00e6kker. Overheadet ved at \u00e5bne denne forbindelse er stort. Og for at v\u00e6re \u00e6rlig, har jeg ikke dykket ned i denne retning. Jeg har optimeret batching, men ikke COPY. <\/p>\n<p><\/p>\n<p>Hvad g\u00f8r vi n\u00e6ste? Vi m\u00e5ler. Vi forst\u00e5r, at vi skal bruge enten strukturer eller en smart batch, der samler flere v\u00e6rdier. <\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"PostgreSQL og JDBC, vi klemmer alt ud af det. Vladimir Sitnikov\" src=\"\/wp-content\/uploads\/2020\/05\/e02fa2574e2d1b678382db15064610d3.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>Hvad skal man tage med fra dagens rapport?<\/p>\n<p><\/p>\n<ul>\n<li>PreparedStatement er alt for os. Det giver meget for ydeevnen. Det medf\u00f8rer en stor dunk af tj\u00e6re. <\/li>\n<li>Og vi skal lave EXPLAIN ANALYZE 6 gange.<\/li>\n<li>Og vi skal blande OFFSET 0, og tricks som +0 for at justere den resterende procent af vores problematiske foresp\u00f8rgsler.<\/li>\n<\/ul>\n<p>Kilde: <a content=\"nofollow\" rel=\"nofollow\" href=\"https:\/\/habr.com\/ru\/post\/499794\/\">habr.com<\/a> <\/p>","protected":false,"gt_translate_keys":[{"key":"rendered","format":"html"}]},"excerpt":{"rendered":"<p>\u041f\u0440\u0435\u0434\u043b\u0430\u0433\u0430\u044e \u043e\u0437\u043d\u0430\u043a\u043e\u043c\u0438\u0442\u044c\u0441\u044f \u0441 \u0440\u0430\u0441\u0448\u0438\u0444\u0440\u043e\u0432\u043a\u043e\u0439 \u0434\u043e\u043a\u043b\u0430\u0434\u0430 \u043d\u0430\u0447\u0430\u043b\u0430 2016 \u0433\u043e\u0434\u0430 \u0412\u043b\u0430\u0434\u0438\u043c\u0438\u0440\u0430 \u0421\u0438\u0442\u043d\u0438\u043a\u043e\u0432\u0430 &quot;PostgreSQL \u0438 JDBC \u0432\u044b\u0436\u0438\u043c\u0430\u0435\u043c \u0432\u0441\u0435 \u0441\u043e\u043a\u0438&quot; \u0414\u043e\u0431\u0440\u044b\u0439 \u0434\u0435\u043d\u044c! \u041c\u0435\u043d\u044f \u0437\u043e\u0432\u0443\u0442 \u0412\u043b\u0430\u0434\u0438\u043c\u0438\u0440 \u0421\u0438\u0442\u043d\u0438\u043a\u043e\u0432. \u042f \u0440\u0430\u0431\u043e\u0442\u0430\u044e 10 \u043b\u0435\u0442 \u0432 \u043a\u043e\u043c\u043f\u0430\u043d\u0438\u0438 NetCracker. \u0418 \u0432 \u043e\u0441\u043d\u043e\u0432\u043d\u043e\u043c \u044f \u0437\u0430\u043d\u0438\u043c\u0430\u044e\u0441\u044c \u043f\u0440\u043e\u0438\u0437\u0432\u043e\u0434\u0438\u0442\u0435\u043b\u044c\u043d\u043e\u0441\u0442\u044c\u044e. \u0412\u0441\u0435, \u0447\u0442\u043e \u0441\u0432\u044f\u0437\u0430\u043d\u043e \u0441 Java, \u0432\u0441\u0435, \u0447\u0442\u043e \u0441\u0432\u044f\u0437\u0430\u043d\u043e \u0441 SQL \u2013 \u044d\u0442\u043e \u0442\u043e, \u0447\u0442\u043e \u044f \u043b\u044e\u0431\u043b\u044e. \u0418 \u0441\u0435\u0433\u043e\u0434\u043d\u044f \u044f \u0440\u0430\u0441\u0441\u043a\u0430\u0436\u0443 [&hellip;]<\/p>\n","protected":false,"gt_translate_keys":[{"key":"rendered","format":"html"}]},"author":1,"featured_media":79894,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[688],"tags":[],"class_list":["post-79893","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-administrirovanie"],"aioseo_notices":[],"aioseo_head":"\n\t\t<!-- All in One SEO 5.0.3 - aioseo.com -->\n\t<meta name=\"description\" content=\"\u041f\u0440\u0435\u0434\u043b\u0430\u0433\u0430\u044e \u043e\u0437\u043d\u0430\u043a\u043e\u043c\u0438\u0442\u044c\u0441\u044f \u0441 \u0440\u0430\u0441\u0448\u0438\u0444\u0440\u043e\u0432\u043a\u043e\u0439 \u0434\u043e\u043a\u043b\u0430\u0434\u0430 \u043d\u0430\u0447\u0430\u043b\u0430 2016 \u0433\u043e\u0434\u0430 \u0412\u043b\u0430\u0434\u0438\u043c\u0438\u0440\u0430 \u0421\u0438\u0442\u043d\u0438\u043a\u043e\u0432\u0430 &quot;PostgreSQL \u0438 JDBC \u0432\u044b\u0436\u0438\u043c\u0430\u0435\u043c \u0432\u0441\u0435 \u0441\u043e\u043a\u0438&quot;\" \/>\n\t<meta name=\"robots\" content=\"max-image-preview:large\" \/>\n\t<meta name=\"author\" content=\"Yuri Gagarin\"\/>\n\t<link rel=\"canonical\" href=\"https:\/\/prohoster.info\/da\/blog\/administrirovanie\/postgresql-i-jdbc-vyzhimaem-vse-soki-vladimir-sitnikov\" \/>\n\t\t<meta name=\"generator\" content=\"All in One SEO (AIOSEO) 5.0.3\" \/>\n\t\t<meta property=\"og:locale\" content=\"da_DK\" \/>\n\t\t<meta property=\"og:site_name\" content=\"ProHoster | \u041a\u0443\u043f\u0438\u0442\u044c \u043d\u0430\u0434\u0435\u0436\u043d\u044b\u0439 \u0445\u043e\u0441\u0442\u0438\u043d\u0433 \u0434\u043b\u044f \u0441\u0430\u0439\u0442\u043e\u0432 \u0441 \u0437\u0430\u0449\u0438\u0442\u043e\u0439 \u043e\u0442 DDoS, VPS VDS \u0441\u0435\u0440\u0432\u0435\u0440\u044b\" \/>\n\t\t<meta property=\"og:type\" content=\"article\" \/>\n\t\t<meta property=\"og:title\" content=\"\ud83e\udd47PostgreSQL \u0438 JDBC \u0432\u044b\u0436\u0438\u043c\u0430\u0435\u043c \u0432\u0441\u0435 \u0441\u043e\u043a\u0438. \u0412\u043b\u0430\u0434\u0438\u043c\u0438\u0440 \u0421\u0438\u0442\u043d\u0438\u043a\u043e\u0432 | ProHoster\" \/>\n\t\t<meta property=\"og:description\" content=\"\u041f\u0440\u0435\u0434\u043b\u0430\u0433\u0430\u044e \u043e\u0437\u043d\u0430\u043a\u043e\u043c\u0438\u0442\u044c\u0441\u044f \u0441 \u0440\u0430\u0441\u0448\u0438\u0444\u0440\u043e\u0432\u043a\u043e\u0439 \u0434\u043e\u043a\u043b\u0430\u0434\u0430 \u043d\u0430\u0447\u0430\u043b\u0430 2016 \u0433\u043e\u0434\u0430 \u0412\u043b\u0430\u0434\u0438\u043c\u0438\u0440\u0430 \u0421\u0438\u0442\u043d\u0438\u043a\u043e\u0432\u0430 &quot;PostgreSQL \u0438 JDBC \u0432\u044b\u0436\u0438\u043c\u0430\u0435\u043c \u0432\u0441\u0435 \u0441\u043e\u043a\u0438&quot;\" \/>\n\t\t<meta property=\"og:url\" content=\"https:\/\/prohoster.info\/da\/blog\/administrirovanie\/postgresql-i-jdbc-vyzhimaem-vse-soki-vladimir-sitnikov\" \/>\n\t\t<meta property=\"og:image\" content=\"https:\/\/prohoster.info\/wp-content\/uploads\/2021\/11\/logo-350.jpg\" \/>\n\t\t<meta property=\"og:image:secure_url\" content=\"https:\/\/prohoster.info\/wp-content\/uploads\/2021\/11\/logo-350.jpg\" \/>\n\t\t<meta property=\"og:image:width\" content=\"350\" \/>\n\t\t<meta property=\"og:image:height\" content=\"350\" \/>\n\t\t<meta property=\"article:published_time\" content=\"2020-05-01T11:43:12+00:00\" \/>\n\t\t<meta property=\"article:modified_time\" content=\"2020-05-01T11:43:12+00:00\" \/>\n\t\t<meta property=\"article:publisher\" content=\"https:\/\/www.facebook.com\/prohoster\" \/>\n\t\t<meta property=\"article:author\" content=\"https:\/\/www.facebook.com\/prohoster\" \/>\n\t\t<!-- All in One SEO -->\n\n","aioseo_head_json":{"title":"\ud83e\udd47PostgreSQL og JDBC presser vi alt ud af. Vladimir Sitnikov | ProHoster","description":"Jeg vil gerne invitere dig til at gennemg\u00e5 transskriptionen af Vladimir Sitnikovs rapport fra begyndelsen af 2016 \"PostgreSQL og JDBC - vi presser det hele ud\"","canonical_url":"https:\/\/prohoster.info\/da\/blog\/administrirovanie\/postgresql-i-jdbc-vyzhimaem-vse-soki-vladimir-sitnikov","robots":"max-image-preview:large","keywords":"","webmasterTools":{"miscellaneous":""},"schema":null,"og:locale":"da_DK","og:site_name":"ProHoster | \u041a\u0443\u043f\u0438\u0442\u044c \u043d\u0430\u0434\u0435\u0436\u043d\u044b\u0439 \u0445\u043e\u0441\u0442\u0438\u043d\u0433 \u0434\u043b\u044f \u0441\u0430\u0439\u0442\u043e\u0432 \u0441 \u0437\u0430\u0449\u0438\u0442\u043e\u0439 \u043e\u0442 DDoS, VPS VDS \u0441\u0435\u0440\u0432\u0435\u0440\u044b","og:type":"article","og:title":"\ud83e\udd47PostgreSQL \u0438 JDBC \u0432\u044b\u0436\u0438\u043c\u0430\u0435\u043c \u0432\u0441\u0435 \u0441\u043e\u043a\u0438. \u0412\u043b\u0430\u0434\u0438\u043c\u0438\u0440 \u0421\u0438\u0442\u043d\u0438\u043a\u043e\u0432 | ProHoster","og:description":"\u041f\u0440\u0435\u0434\u043b\u0430\u0433\u0430\u044e \u043e\u0437\u043d\u0430\u043a\u043e\u043c\u0438\u0442\u044c\u0441\u044f \u0441 \u0440\u0430\u0441\u0448\u0438\u0444\u0440\u043e\u0432\u043a\u043e\u0439 \u0434\u043e\u043a\u043b\u0430\u0434\u0430 \u043d\u0430\u0447\u0430\u043b\u0430 2016 \u0433\u043e\u0434\u0430 \u0412\u043b\u0430\u0434\u0438\u043c\u0438\u0440\u0430 \u0421\u0438\u0442\u043d\u0438\u043a\u043e\u0432\u0430 &quot;PostgreSQL \u0438 JDBC \u0432\u044b\u0436\u0438\u043c\u0430\u0435\u043c \u0432\u0441\u0435 \u0441\u043e\u043a\u0438&quot;","og:url":"https:\/\/prohoster.info\/da\/blog\/administrirovanie\/postgresql-i-jdbc-vyzhimaem-vse-soki-vladimir-sitnikov","og:image":"https:\/\/prohoster.info\/wp-content\/uploads\/2021\/11\/logo-350.jpg","og:image:secure_url":"https:\/\/prohoster.info\/wp-content\/uploads\/2021\/11\/logo-350.jpg","og:image:width":350,"og:image:height":350,"article:published_time":"2020-05-01T11:43:12+00:00","article:modified_time":"2020-05-01T11:43:12+00:00","article:publisher":"https:\/\/www.facebook.com\/prohoster","article:author":"https:\/\/www.facebook.com\/prohoster"},"aioseo_meta_data":{"post_id":"79893","title":null,"description":null,"keywords":null,"keyphrases":null,"primary_term":null,"canonical_url":null,"og_title":null,"og_description":null,"og_object_type":"default","og_image_type":"default","og_image_url":null,"og_image_width":null,"og_image_height":null,"og_image_custom_url":null,"og_image_custom_fields":null,"og_video":null,"og_custom_url":null,"og_article_section":null,"og_article_tags":null,"twitter_use_og":false,"twitter_card":"default","twitter_image_type":"default","twitter_image_url":null,"twitter_image_custom_url":null,"twitter_image_custom_fields":null,"twitter_title":null,"twitter_description":null,"schema":{"blockGraphs":[],"customGraphs":[],"default":{"data":{"Article":[],"Course":[],"Dataset":[],"FAQPage":[],"Movie":[],"Person":[],"Product":[],"ProductReview":[],"Car":[],"Recipe":[],"Service":[],"SoftwareApplication":[],"WebPage":[]},"graphName":"","isEnabled":true},"graphs":[]},"schema_type":null,"schema_type_options":null,"pillar_content":false,"robots_default":true,"robots_noindex":false,"robots_noarchive":false,"robots_nosnippet":false,"robots_nofollow":false,"robots_noimageindex":false,"robots_noodp":false,"robots_notranslate":false,"robots_max_snippet":null,"robots_max_videopreview":null,"robots_max_imagepreview":"large","priority":null,"frequency":null,"local_seo":null,"seo_analyzer_scan_date":null,"breadcrumb_settings":null,"limit_modified_date":false,"reviewed_by":null,"ai":null,"created":"2021-02-28 16:29:39","updated":"2022-10-10 00:32:43","focus_keyword":null,"additional_keywords":null,"truseo_locale":null},"gt_translate_keys":[{"key":"link","format":"url"}],"_links":{"self":[{"href":"https:\/\/prohoster.info\/da\/wp-json\/wp\/v2\/posts\/79893","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/prohoster.info\/da\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/prohoster.info\/da\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/prohoster.info\/da\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/prohoster.info\/da\/wp-json\/wp\/v2\/comments?post=79893"}],"version-history":[{"count":0,"href":"https:\/\/prohoster.info\/da\/wp-json\/wp\/v2\/posts\/79893\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/prohoster.info\/da\/wp-json\/wp\/v2\/media\/79894"}],"wp:attachment":[{"href":"https:\/\/prohoster.info\/da\/wp-json\/wp\/v2\/media?parent=79893"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/prohoster.info\/da\/wp-json\/wp\/v2\/categories?post=79893"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/prohoster.info\/da\/wp-json\/wp\/v2\/tags?post=79893"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}