{"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\/no\/blog\/administrirovanie\/postgresql-i-jdbc-vyzhimaem-vse-soki-vladimir-sitnikov","title":{"rendered":"PostgreSQL og JDBC \u2013 vi presser alt ut. Vladimir Sitnikov","gt_translate_keys":[{"key":"rendered","format":"text"}]},"content":{"rendered":"<p><strong>Jeg tilbyr en gjennomgang av Vladimir Sitnikovs rapport fra begynnelsen av 2016 med tittelen \"PostgreSQL og JDBC: vi presser ut alt som er mulig\"<\/strong><\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"PostgreSQL og JDBC \u2013 vi presser alt ut. 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 \u2013 vi presser alt ut. Vladimir Sitnikov\" src=\"\/wp-content\/uploads\/2020\/05\/030666abda53aa388b1cb1d0c46a7524.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>God dag! Jeg heter Vladimir Sitnikov. Jeg har jobbet i 10 \u00e5r i NetCracker. Og jeg jobber hovedsakelig med ytelse. Alt som har med Java \u00e5 gj\u00f8re, og alt som har med SQL \u00e5 gj\u00f8re \u2013 det er det jeg elsker. <\/p>\n<p><\/p>\n<p>I dag vil jeg snakke om hva vi har st\u00f8tt p\u00e5 i selskapet n\u00e5r vi begynte \u00e5 bruke PostgreSQL som database-server. Og vi jobber hovedsakelig med Java. Men det jeg vil si i dag, gjelder ikke bare Java. Som praksisen har vist, oppst\u00e5r det ogs\u00e5 i andre spr\u00e5k. <\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"PostgreSQL og JDBC \u2013 vi presser alt ut. Vladimir Sitnikov\" src=\"\/wp-content\/uploads\/2020\/05\/b01a214d782c7e32797a6c6466457979.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>Vi skal snakke om:<\/p>\n<p><\/p>\n<ul>\n<li>datauthenting. <\/li>\n<li>lagring av data. <\/li>\n<li>og ytelse. <\/li>\n<li>Og om feller som er der. <\/li>\n<\/ul>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"PostgreSQL og JDBC \u2013 vi presser alt ut. Vladimir Sitnikov\" src=\"\/wp-content\/uploads\/2020\/05\/57da0c6aa4bb62e1beb77160f5aee7e7.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>La oss starte med et enkelt sp\u00f8rsm\u00e5l. Vi henter \u00e9n rad fra tabellen basert p\u00e5 prim\u00e6rn\u00f8kkelen. <\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"PostgreSQL og JDBC \u2013 vi presser alt ut. Vladimir Sitnikov\" src=\"\/wp-content\/uploads\/2020\/05\/d5fcb1172aef402a87064498bf8a5218.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>Databasen er p\u00e5 den samme verten. Og alt dette tar 20 millisekunder.<\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"PostgreSQL og JDBC \u2013 vi presser alt ut. Vladimir Sitnikov\" src=\"\/wp-content\/uploads\/2020\/05\/103b7f9736b82a3313491b2f0d2a5824.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>Disse 20 millisekundene er veldig mye. Hvis du har 100 slike foresp\u00f8rselere, bruker du tid i sekunder p\u00e5 \u00e5 kj\u00f8re disse foresp\u00f8rselene, det vil si at du kaster bort tid.<\/p>\n<p><\/p>\n<p>Vi liker ikke \u00e5 gj\u00f8re dette, og ser p\u00e5 hva databasen tilbyr oss for \u00e5 gj\u00f8re det. Databasen gir oss to m\u00e5ter \u00e5 utf\u00f8re foresp\u00f8rselen p\u00e5. <\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"PostgreSQL og JDBC \u2013 vi presser alt ut. 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 m\u00e5ten \u2013 en enkel foresp\u00f8rsel. Hva er bra med dette? Jo, vi sender den og gj\u00f8r ingenting mer. <\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"PostgreSQL og JDBC \u2013 vi presser alt ut. 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 utvidet foresp\u00f8rsel, som er mer intelligent, men mer funksjonell. Du kan sende foresp\u00f8rselen p\u00e5 parsing, utf\u00f8relse, binding av variabler osv. separat. <\/p>\n<p><\/p>\n<p>Super utvidet foresp\u00f8rsel \u2013 dette er noe vi ikke vil dekke i denne presentasjonen. Vi \u00f8nsker kanskje noen ting fra databasen, og det er en liste over \u00f8nsker som har blitt dannet p\u00e5 en eller annen m\u00e5te, det vil si dette er det vi \u00f8nsker, men som ikke er mulig akkurat n\u00e5 og i l\u00f8pet av det n\u00e6rmeste \u00e5ret. S\u00e5 vi har bare skrevet det ned og vil g\u00e5 for \u00e5 skape oppstyr blant hovedpersonene.<\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"PostgreSQL og JDBC \u2013 vi presser alt ut. 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 gj\u00f8re, er enkel foresp\u00f8rsel og utvidet foresp\u00f8rsel.<\/p>\n<p><\/p>\n<p>Hva er spesialiteten til hver tiln\u00e6rming? <\/p>\n<p><\/p>\n<p>En enkel foresp\u00f8rsel er godt egnet for engangsbruk. Du utf\u00f8rer den \u00e9n gang og glemmer den. Problemet er at den ikke st\u00f8tter bin\u00e6rt dataformat, det vil si at den ikke er egnet for noen h\u00f8yytelsessystemer.<\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"PostgreSQL og JDBC \u2013 vi presser alt ut. Vladimir Sitnikov\" src=\"\/wp-content\/uploads\/2020\/05\/062c0e45cefd91ece331a306a7651bde.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>Utvidet foresp\u00f8rsel \u2013 gir oss muligheten til \u00e5 spare tid p\u00e5 parsing. Dette er noe vi har implementert og begynt \u00e5 bruke. Det har hjulpet oss enormt. Det er ikke bare tidsbesparelsen fra parsing. Det er ogs\u00e5 besparelse p\u00e5 datatransmisjon, da det er mye mer effektivt \u00e5 overf\u00f8re data i bin\u00e6rt format. <\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"PostgreSQL og JDBC \u2013 vi presser alt ut. Vladimir Sitnikov\" src=\"\/wp-content\/uploads\/2020\/05\/6df83a2f3736568668cf9d74de5d9758.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>La oss g\u00e5 over til praksis. Slik ser en typisk applikasjon ut. Det kan v\u00e6re Java osv. <\/p>\n<p><\/p>\n<p>Vi opprettet en statement. Vi utf\u00f8rte kommandoen. Vi opprettet en close. Hvor ligger feilen her? Hva er problemet? Det er ingen problemer. Dette st\u00e5r det i alle b\u00f8kene. Dette m\u00e5 man skrive. Hvis du \u00f8nsker maksimal ytelse, s\u00e5 skriv p\u00e5 denne m\u00e5ten. <\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"PostgreSQL og JDBC \u2013 vi presser alt ut. Vladimir Sitnikov\" src=\"\/wp-content\/uploads\/2020\/05\/6923293946dec45b3fd508235728ab95.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>Men praksisen har vist at dette ikke fungerer. Hvorfor? Fordi vi har metoden \u00abclose\u00bb. Og n\u00e5r vi gj\u00f8r det slik, blir det fra databasen sett p\u00e5 som \u00e5 v\u00e6re en r\u00f8yker som jobber med databasen. Vi sa \u00abPARSE EXECUTE DEALLOCATE\u00bb.<\/p>\n<p><\/p>\n<p>Hvorfor disse un\u00f8dvendige opprettelsene og utlastingene av statements? De er ingen til hjelp. Men vanligvis skjer det slik i PreparedStatement, at n\u00e5r vi stenger dem, s\u00e5 stenger de alt i databasen. Dette er ikke det vi \u00f8nsker. <\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"PostgreSQL og JDBC \u2013 vi presser alt ut. Vladimir Sitnikov\" src=\"\/wp-content\/uploads\/2020\/05\/5a357a209e414024c437d042f600f251.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>Vi \u00f8nsker \u00e5 jobbe med databasen som friske mennesker. Vi forbereder statement \u00e9n gang, og deretter bruker vi det mange ganger. Faktisk mange ganger \u2013 det er \u00e9n gang i hele livssyklusen til applikasjonen at vi parser. Og p\u00e5 de forskjellige REST-ene bruker vi den samme statement ID-en. Det er v\u00e5rt m\u00e5l. <\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"PostgreSQL og JDBC \u2013 vi presser alt ut. 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 oppn\u00e5 dette? <\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"PostgreSQL og JDBC \u2013 vi presser alt ut. Vladimir Sitnikov\" src=\"\/wp-content\/uploads\/2020\/05\/0f101d890d1a2af8e99f8a3a8a06fd5a.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>Veldig enkelt \u2013 vi trenger ikke \u00e5 lukke statements. Vi skriver slik: \u00abprepare\u00bb \u00abexecute\u00bb. <\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"PostgreSQL og JDBC \u2013 vi presser alt ut. 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 \u2013 vi presser alt ut. Vladimir Sitnikov\" src=\"\/wp-content\/uploads\/2020\/05\/724646bfc55b5e2b611b1584ca8ba6aa.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>Hvis vi kj\u00f8rer dette, s\u00e5 er det klart at vi et sted vil oppleve noe som overfyller. Hvis ikke det er klart, kan vi m\u00e5le. La oss lage en benchmark, hvor en s\u00e5 enkel metode er inkludert. Vi oppretter en statement. Kj\u00f8r den p\u00e5 en viss versjon av driveren, og vi ser at den faller ganske raskt med tap av all minne som vi har tapt. <\/p>\n<p><\/p>\n<p>Det er klart at slike feil lett kan rettes. Jeg skal ikke snakke om dem. Men jeg vil si at i den nye versjonen fungerer det mye raskere. Metoden er ubrukelig, men likevel. <\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"PostgreSQL og JDBC \u2013 vi presser alt ut. Vladimir Sitnikov\" src=\"\/wp-content\/uploads\/2020\/05\/b232a6205e708c70f52be0024bbe9980.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>Hvordan arbeide p\u00e5 riktig m\u00e5te? Hva m\u00e5 vi gj\u00f8re?<\/p>\n<p><\/p>\n<p>I virkeligheten lukker applikasjoner alltid statements. I alle b\u00f8ker anbefales det \u00e5 lukke dem, ellers vil minne lekke. <\/p>\n<p><\/p>\n<p>Og PostgreSQL kan ikke cache foresp\u00f8rslene. Hver sesjon m\u00e5 opprette denne cachen for seg selv. <\/p>\n<p><\/p>\n<p>Og vi \u00f8nsker heller ikke \u00e5 kaste bort tid p\u00e5 parsing. <\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"PostgreSQL og JDBC \u2013 vi presser alt ut. Vladimir Sitnikov\" src=\"\/wp-content\/uploads\/2020\/05\/85b9574938aa6e6bf59c956e3728bdc3.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>Og som vanlig har vi to alternativer. <\/p>\n<p><\/p>\n<p>Den f\u00f8rste l\u00f8sningen er at vi tar og sier at vi skal pakke alt inn i PgSQL. Der finnes det cache. Det cacher alt. Det vil bli str\u00e5lende. Vi har sett p\u00e5 dette. Vi har 100500 foresp\u00f8rslene. Det fungerer ikke. Vi er ikke enige i \u00e5 gj\u00f8re foresp\u00f8rslene om til prosedyrer for h\u00e5nd. Nei-nei. <\/p>\n<p><\/p>\n<p>Vi har en andre l\u00f8sning \u2013 ta og lage noe selv. Vi \u00e5pner kildene og begynner \u00e5 kode. Koder-koder. Det viste seg at det ikke var s\u00e5 vanskelig \u00e5 gj\u00f8re. <\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"PostgreSQL og JDBC \u2013 vi presser alt ut. 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 dukket opp i august 2015. N\u00e5 finnes det allerede en mer moderne versjon. Og alt er flott. Det fungerer s\u00e5 bra at vi ikke endrer noe i applikasjonen. Vi har til og med sluttet \u00e5 tenke p\u00e5 PgSQL, det vil si at dette var mer enn tilstrekkelig til \u00e5 redusere alle driftskostnader praktisk talt til null. <\/p>\n<p><\/p>\n<p>Dermed aktiveres server-forberedte utsagn ved den femte kj\u00f8ringen for \u00e5 ikke kaste bort minne i databasen p\u00e5 hver enkelt engangsforesp\u00f8rsel. <\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"PostgreSQL og JDBC \u2013 vi presser alt ut. 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\u00f8rre \u2013 hvor er tallene? Hva f\u00e5r dere? Og her kan jeg ikke gi tall, for hver foresp\u00f8rsel har sine egne tall.<\/p>\n<p><\/p>\n<p>V\u00e5re foresp\u00f8rsel var slik at vi p\u00e5 OLTP-foresp\u00f8rslene brukte omtrent 20 millisekunder p\u00e5 parsing. Det var 0,5 millisekunder p\u00e5 kj\u00f8ring, 20 millisekunder p\u00e5 parsing. Foresp\u00f8rselen var 10 KiB med tekst, 170 linjer med plan. Dette er en OLTP-foresp\u00f8rsel. Den ber om 1, 5, 10 linjer, av og til mer. <\/p>\n<p><\/p>\n<p>Men vi \u00f8nsket absolutt ikke \u00e5 bruke 20 millisekunder. Vi klarte \u00e5 redusere det til 0. Alt er flott. <\/p>\n<p><\/p>\n<p>Hva kan dere ta med dere herfra? Hvis dere bruker Java, s\u00e5 tar dere den moderne versjonen av driveren og er forn\u00f8yd. <\/p>\n<p><\/p>\n<p>Hvis dere bruker et annet spr\u00e5k, s\u00e5 tenk \u2013 kanskje dette ogs\u00e5 er noe dere trenger? Fordi fra perspektivet til det endelige spr\u00e5ket, for eksempel hvis det er PL 8 eller har dere LibPQ, s\u00e5 er det ikke \u00e5penbart at dere bruker tid ikke p\u00e5 kj\u00f8ringen, men p\u00e5 parsing, og det er verdt \u00e5 sjekke. Hvordan? Alt er gratis. <\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"PostgreSQL og JDBC \u2013 vi presser alt ut. Vladimir Sitnikov\" src=\"\/wp-content\/uploads\/2020\/05\/fda6b1c1b126cb85c970e42335e1dc24.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>Unntatt at det er feil, noen spesielle forhold. Og om dem skal vi akkurat n\u00e5 snakke. St\u00f8rstedelen vil v\u00e6re om industriell arkeologi, om det vi har funnet, hva vi har st\u00f8tt p\u00e5. <\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"PostgreSQL og JDBC \u2013 vi presser alt ut. Vladimir Sitnikov\" src=\"\/wp-content\/uploads\/2020\/05\/9a3b383f83c5e227cd02952c5825b64f.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>Hvis foresp\u00f8rselen genereres dynamisk. Slike ting skjer. Noen limer sammen strenger, og det blir en SQL-foresp\u00f8rsel.<\/p>\n<p><\/p>\n<p>Hva er feil med det? Det er d\u00e5rlig fordi vi hver gang ender opp med en annen streng.<\/p>\n<p><\/p>\n<p>Og denne varierte strengen m\u00e5 hashCode beregnes p\u00e5 nytt. Dette er virkelig en CPU-oppgave \u2013 \u00e5 finne den lange foresp\u00f8rselsteksten er ikke s\u00e5 enkelt selv med eksisterende hash. S\u00e5 konklusjonen er enkel \u2013 ikke generer foresp\u00f8rslene. Oppbevar dem i en enkelt variabel. Og v\u00e6r glad.<\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"PostgreSQL og JDBC \u2013 vi presser alt ut. Vladimir Sitnikov\" src=\"\/wp-content\/uploads\/2020\/05\/bcd4f729204cecdb572a98f357bcc33f.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>Neste problem. Datatyper er viktige. Det finnes ORM-er som sier at hvilken som helst NULL er greit. Hvis det er Int, sier vi setInt. Og hvis NULL, s\u00e5 skal det alltid v\u00e6re VARCHAR. Og hva gj\u00f8r det vel til slutt hvilken NULL som er der? Databasen forst\u00e5r dette selv. <\/p>\n<p><\/p>\n<p>I praksis er databasen fullstendig klar over dette. <strong>Hvis du f\u00f8rst sa at dette er et tall, og etterp\u00e5 sa at det er VARCHAR, s\u00e5 er det umulig \u00e5 gjenbruke server-forberedte setninger. I s\u00e5 fall m\u00e5 vi opprette setningen v\u00e5r p\u00e5 nytt.<\/strong><\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"PostgreSQL og JDBC \u2013 vi presser alt ut. Vladimir Sitnikov\" src=\"\/wp-content\/uploads\/2020\/05\/552d9c2e25cf9abbdfef12c98d027740.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>Hvis du kj\u00f8rer den samme foresp\u00f8rselen, s\u00e5 v\u00e6r oppmerksom p\u00e5 at datatype i kolonnene ikke er forvirret. Du m\u00e5 passe p\u00e5 NULL. Dette er en vanlig feil vi hadde etter at vi begynte \u00e5 bruke PreparedStatements.<\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"PostgreSQL og JDBC \u2013 vi presser alt ut. Vladimir Sitnikov\" src=\"\/wp-content\/uploads\/2020\/05\/5d73c8f5dfa281c3bda962fc3e5edd84.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>Greit, vi skrudde det p\u00e5. Kanskje vi fikk driveren. Og ytelsen falt. Alt ble d\u00e5rlig. <\/p>\n<p><\/p>\n<p>Hvordan kan dette skje? Er det en bug eller en funksjon? Dessverre er det ikke mulig \u00e5 forst\u00e5 \u2013 er dette en bug eller en funksjon. Men det finnes et ganske enkelt gjenskprehendingsscenario for dette problemet. Det angrep oss ganske uventet. Og det handler om en foresp\u00f8rsel fra bokstavelig talt \u00e9n tabell. Vi hadde selvf\u00f8lgelig flere slike foresp\u00f8rslene. De inkluderte som regel to-tre tabeller, men det finnes dette scenariet. Ta databasen din i hvilken som helst versjon og gjenskap.<\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"PostgreSQL og JDBC \u2013 vi presser alt ut. 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>Poenget er at vi har to kolonner, hvor hver er indeksert. I den ene kolonnen finnes det en million rader med NULL-verdi. Og i den andre kolonnen ligger det bare 20 rader. N\u00e5r vi kj\u00f8rer uten tilknyttede variabler, fungerer alt som det skal. <\/p>\n<p><\/p>\n<p>Hvis vi begynner \u00e5 kj\u00f8re med tilknyttede variabler, det vil si vi bruker tegn som \u00ab?\u00bb eller \u00ab$1\u00bb i foresp\u00f8rselen, hva f\u00e5r vi da?<\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"PostgreSQL og JDBC \u2013 vi presser alt ut. 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>F\u00f8rste kj\u00f8ring \u2013 som forventet. Andre \u2013 litt raskere. Noe ble cachet. Tredje-fjerde-femte. S\u00e5, bang \u2013 og p\u00e5 en eller annen m\u00e5te s\u00e5nn. Og det mest frustrerende er at dette skjer ved den sjette kj\u00f8ringen. Hvem visste at man m\u00e5tte gj\u00f8re akkurat seks kj\u00f8ringer for \u00e5 forst\u00e5 hvilken utf\u00f8relsesplan som faktisk gjelder?<\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"PostgreSQL og JDBC \u2013 vi presser alt ut. Vladimir Sitnikov\" src=\"\/wp-content\/uploads\/2020\/05\/893c955bc1e2e15a6986690e516f72a9.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>Hvem har skylden? Hva skjedde? Databasen inneholder optimalisering. Og den er p\u00e5 en m\u00e5te optimalisert for et generisk tilfelle. Og, i s\u00e5 fall, fra et visst punkt overg\u00e5r den til den generiske planen, som dessverre kan vise seg \u00e5 v\u00e6re noe annet. Den kan v\u00e6re lik, men kan ogs\u00e5 v\u00e6re noe annet. Og det er et terskelverdi som f\u00f8rer til slik oppf\u00f8rsel. <\/p>\n<p><\/p>\n<p>Hva kan vi gj\u00f8re med dette? Her er det selvf\u00f8lgelig mer komplisert \u00e5 gj\u00f8re antakelser. Det er en enkel l\u00f8sning som vi bruker. Det er +0, OFFSET 0. Du kjenner sikkert slike l\u00f8sninger. Vi tar bare og legger til \u00ab+0\u00bb i foresp\u00f8rselen, og s\u00e5 g\u00e5r det bra. Jeg skal vise det senere. <\/p>\n<p><\/p>\n<p>Og det er en annen mulighet \u2013 se mer n\u00f8ye p\u00e5 planene. Utvikleren m\u00e5 ikke bare skrive foresp\u00f8rselen, men ogs\u00e5 si \u00abexplain analyze\u00bb seks ganger. Hvis det er fem, er det ikke tilstrekkelig. <\/p>\n<p><\/p>\n<p>Og det er en tredje mulighet \u2013 \u00e5 skrive et brev til pgsql-hackers. Jeg skrev det, men det er fortsatt uklart om det er en feil eller en funksjon.<\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"PostgreSQL og JDBC \u2013 vi presser alt ut. 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 tenker \u2013 er dette en feil eller en funksjon, la oss fikse det. Vi tar foresp\u00f8rselen v\u00e5r og legger til \u00ab+0\u00bb. Det g\u00e5r bra. To symboler og vi trenger ikke engang \u00e5 tenke p\u00e5 hvordan det fungerer. Veldig enkelt. Vi har bare nektet databasen \u00e5 bruke indeksen for denne kolonnen. Vi har ikke indeksen for kolonnen \u00ab+0\u00bb og alt er bra. <\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"PostgreSQL og JDBC \u2013 vi presser alt ut. Vladimir Sitnikov\" src=\"\/wp-content\/uploads\/2020\/05\/5261d80d084786a15b9764f6367014cd.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>Det er regelen om seks forklaringer. N\u00e5, i de n\u00e5v\u00e6rende versjonene m\u00e5 du gj\u00f8re det seks ganger hvis du har relaterte variabler. Hvis du ikke har relaterte variabler, gj\u00f8r vi det slik. Og til slutt feiler akkurat denne foresp\u00f8rselen. Det er ikke s\u00e5 vanskelig.<\/p>\n<p><\/p>\n<p>Det kunne virke som om det er nok n\u00e5? Her er en feil, der en feil. Det er faktisk feil overalt. <\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"PostgreSQL og JDBC \u2013 vi presser alt ut. Vladimir Sitnikov\" src=\"\/wp-content\/uploads\/2020\/05\/674dc7e7b4624baa5c79eee9e1e89db0.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>La oss se n\u00e6rmere p\u00e5 det. For eksempel har vi to skjemaer. Skjema A med tabellen Y og skjema B med tabellen Y. Foresp\u00f8rselen \u2013 velg data fra tabellen. Hva skjer da? Vi f\u00e5r en feil. Vi f\u00e5r alt som er nevnt ovenfor. Regelen er \u2013 feil overalt, og vi f\u00e5r alt nevnt ovenfor.<\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"PostgreSQL og JDBC \u2013 vi presser alt ut. Vladimir Sitnikov\" src=\"\/wp-content\/uploads\/2020\/05\/dd6f544bb9e930c39e36523c9afe6003.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>N\u00e5 er sp\u00f8rsm\u00e5let: \u00abHvorfor?\u00bb. Det kunne virke som om det finnes dokumentasjon som sier at hvis vi har et skjema, s\u00e5 er det variabelen \u00absearch_path\u00bb, som indikerer hvor vi skal lete etter tabellen. Det virker som om variabelen er der.<\/p>\n<p><\/p>\n<p>Hva er problemet? Problemet er at serverforberedte uttalelser ikke vet at \u00absearch_path\u00bb kan endres av noen. Denne verdien forblir som en konstant for databasen. Og noen deler kan kanskje ikke ta opp de nye verdiene. <\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"PostgreSQL og JDBC \u2013 vi presser alt ut. Vladimir Sitnikov\" src=\"\/wp-content\/uploads\/2020\/05\/f738301606d84d72bfa7cc5b568c0df8.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>Selvf\u00f8lgelig avhenger det av versjonen du tester p\u00e5. Det kommer an p\u00e5 hvor mye tabellene dine varierer. Og versjon 9.1 vil bare utf\u00f8re de gamle foresp\u00f8rslene. Nye versjoner kan oppdage fellen og si at du har en feil.<\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"PostgreSQL og JDBC \u2013 vi presser alt ut. 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\">Sett search_path + server-forberedte utsagn =<br \/>\ncachenoppstillingen m\u00e5 ikke endre resultattypen<\/a><\/noindex><\/p>\n<p><\/p>\n<p>Hvordan fikser vi dette? Det er en enkel oppskrift \u2013 ikke gj\u00f8r det. Ikke endre search_path i applikasjonens drift. Hvis du endrer det, er det bedre \u00e5 opprette en ny tilkobling.<\/p>\n<p><\/p>\n<p>Vi kan diskutere, alts\u00e5 \u00e5pne, diskutere, skrive til. Kanskje vi kan overbevise databaseutviklerne om at n\u00e5r noen endrer verdien, b\u00f8r databasen si til klienten: \u00abSe, verdien din har blitt oppdatert. Kanskje du b\u00f8r tilbakestille utsagnene, opprette dem p\u00e5 nytt?\u00bb. N\u00e5 oppf\u00f8rer databasen seg skjult og informerer ikke om at det har skjedd endringer i utsagnene. <\/p>\n<p><\/p>\n<p>Og jeg vil igjen understreke \u2013 dette er ikke typisk for Java. Vi vil se det samme i PL\/pgSQL en til en. Men der vil det bli gjenskapt.<\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"PostgreSQL og JDBC \u2013 vi presser alt ut. Vladimir Sitnikov\" src=\"\/wp-content\/uploads\/2020\/05\/a4e7b201d0c0aa4a0092d2b6ff152df7.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>La oss pr\u00f8ve \u00e5 velge mer data. Vi velger og velger. Vi har en tabell med en million rader. Hver rad er en kilobyte. Omtrent en gigabyte med data. Og vi har arbeidsminne p\u00e5 Java-maskinen p\u00e5 128 megabyte. <\/p>\n<p><\/p>\n<p>Vi, som anbefalt i alle b\u00f8ker, bruker str\u00f8mming. Alts\u00e5 \u00e5pner vi resultSet og leser data derfra litt etter litt. Vil dette fungere? Vil det ikke g\u00e5 tom for minne? Vil det lese litt og litt? La oss stole p\u00e5 databasen, la oss stole p\u00e5 Postgres. Nei, vi stoler ikke. Vil vi f\u00e5 OutOfMemory? Hvem har f\u00e5tt OutOfMemory? Og hvem klarte \u00e5 fikse det etterp\u00e5? Noen klarte \u00e5 fikse det. <\/p>\n<p><\/p>\n<p>Hvis du har en million rader, kan du ikke bare velge p\u00e5 den m\u00e5ten. Du m\u00e5 absolutt bruke OFFSET\/LIMIT. Hvem er for denne varianten? Og hvem er for varianten der man m\u00e5 leke med autoCommit? <\/p>\n<p><\/p>\n<p>Her, som vanlig, viser det seg at det mest uventede alternativet er det rette. Og hvis du plutselig sl\u00e5r av autoCommit, vil det hjelpe. Hvorfor er det slik? Det er vitenskapen ukjent. <\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"PostgreSQL og JDBC \u2013 vi presser alt ut. 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 velger alle klienter som kobler til Postgres-databasen dataene fullt ut. PgJDBC er ikke noe unntak i denne forbindelsen, den velger alle rader.<\/p>\n<p><\/p>\n<p>Det finnes en variant med FetchSize, alts\u00e5 kan du p\u00e5 niv\u00e5et til et enkelt utsagn si at her, v\u00e6r s\u00e5 snill, velg data med 10, 50. Men det fungerer ikke f\u00f8r du sl\u00e5r av autoCommit. Sl\u00e5tt av autoCommit \u2013 det begynner \u00e5 fungere. <\/p>\n<p><\/p>\n<p>Men det er upraktisk \u00e5 g\u00e5 gjennom koden og sette setFetchSize overalt. Derfor har vi laget en innstilling som angir standardverdien for hele forbindelsen.<\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"PostgreSQL og JDBC \u2013 vi presser alt ut. Vladimir Sitnikov\" src=\"\/wp-content\/uploads\/2020\/05\/c9ac8e483dc6bfdbbc300972ee1ab1e0.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>S\u00e5 vi sa dette. Vi har konfigurert parameteren. Og hva fikk vi ut av det? Hvis vi velger et lite antall, for eksempel 10 rader, s\u00e5 har vi ganske store overhead-kostnader. Derfor m\u00e5 denne verdien settes til omtrent hundre. <\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"PostgreSQL og JDBC \u2013 vi presser alt ut. Vladimir Sitnikov\" src=\"\/wp-content\/uploads\/2020\/05\/073e7a4af63688396eefe332ba8261d6.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>Ideelt sett skulle vi ogs\u00e5 l\u00e6re \u00e5 begrense i byte, men oppskriften er slik: sett defaultRowFetchSize til mer enn hundre og v\u00e6r glad. <\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"PostgreSQL og JDBC \u2013 vi presser alt ut. Vladimir Sitnikov\" src=\"\/wp-content\/uploads\/2020\/05\/e3078faf2078fcaec10d6d99872a9990.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>La oss g\u00e5 videre til datainnsending. Innsending er enklere, det finnes forskjellige alternativer. For eksempel, INSERT, VALUES. Det er et godt alternativ. Man kan ogs\u00e5 si 'INSERT SELECT'. I praksis er det det samme. Det er ingen forskjell i ytelse. <\/p>\n<p><\/p>\n<p>B\u00f8ker sier at man m\u00e5 utf\u00f8re Batch-statement, b\u00f8ker sier at man kan utf\u00f8re mer komplekse kommandoer med flere parenteser. Og i Postgres finnes det en fantastisk funksjon - man kan bruke COPY, det vil si \u00e5 gj\u00f8re dette raskere. <\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"PostgreSQL og JDBC \u2013 vi presser alt ut. 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 igjen gj\u00f8re noen interessante oppdagelser. Hvordan \u00f8nsker vi at dette skal fungere? Vi \u00f8nsker \u00e5 unng\u00e5 parsing og un\u00f8dvendige kommandoer. <\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"PostgreSQL og JDBC \u2013 vi presser alt ut. Vladimir Sitnikov\" src=\"\/wp-content\/uploads\/2020\/05\/7b2e4343c51dab3ddb6919bf0f117c4d.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>I praksis gir ikke TCP oss muligheten til dette. Hvis klienten er opptatt med \u00e5 sende en foresp\u00f8rsel, leser ikke databasen foresp\u00f8rslene mens den pr\u00f8ver \u00e5 sende oss svar. Resultatet er at klienten venter p\u00e5 databasen til den leser foresp\u00f8rselen, mens databasen venter p\u00e5 klienten til han leser svaret. <\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"PostgreSQL og JDBC \u2013 vi presser alt ut. Vladimir Sitnikov\" src=\"\/wp-content\/uploads\/2020\/05\/17a062c30ddd83cb890775ec1722044f.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>Derfor er klienten tvunget til \u00e5 sende pakker for synkronisering med jevne mellomrom. Un\u00f8dvendige nettverksinteraksjoner, un\u00f8dvendig tap av tid.<\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"PostgreSQL og JDBC \u2013 vi presser alt ut. Vladimir Sitnikov\" src=\"\/wp-content\/uploads\/2020\/05\/ae7a4f32e2949c1d0550da051937de02.jpg\" style=\"display:block;margin: 0 auto;\" \/>Og jo flere vi legger til, desto verre blir det. Driveren er ganske pessimistisk og legger dem til ganske ofte, omtrent hver 200. linje, avhengig av linjest\u00f8rrelsen, osv. <\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"PostgreSQL og JDBC \u2013 vi presser alt ut. 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>Noen ganger kan du justere bare \u00e9n linje og f\u00e5 ti ganger raskere ytelse. Dette skjer. Hvorfor? Som vanlig, var en slik konstant allerede brukt. Og verdien '128' betydde - ikke bruke batching.<\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"PostgreSQL og JDBC \u2013 vi presser alt ut. 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 bra at dette ikke kom med i den offisielle versjonen. Vi oppdaget det f\u00f8r vi begynte \u00e5 utgi en ny versjon. Alle verdier jeg nevner, er basert p\u00e5 moderne versjoner. <\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"PostgreSQL og JDBC \u2013 vi presser alt ut. Vladimir Sitnikov\" src=\"\/wp-content\/uploads\/2020\/05\/28c82d9e11f6bdaf3cf62b49fc074d68.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>La oss m\u00e5le. Vi m\u00e5ler enkel InsertBatch. Vi m\u00e5ler flere InsertBatch, det vil si det samme, men med mange values. En smart l\u00f8sning. Ikke alle vet hvordan dette gj\u00f8res, men det er en enkel l\u00f8sning, mye enklere enn COPY.<\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"PostgreSQL og JDBC \u2013 vi presser alt ut. Vladimir Sitnikov\" src=\"\/wp-content\/uploads\/2020\/05\/72f7cf6c3b9d9175d3e5a6d5410fe209.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>Man kan bruke COPY.<\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"PostgreSQL og JDBC \u2013 vi presser alt ut. Vladimir Sitnikov\" src=\"\/wp-content\/uploads\/2020\/05\/2b0d8bbcc50f1293c9a8a1eb8eb70d2e.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>Og dette kan gj\u00f8res med strukturer. Deklarer User default type, send inn et array og INSERT direkte i tabellen. <\/p>\n<p><\/p>\n<p>Hvis du \u00e5pner linken: pgjdbc\/ubenchmsrk\/InsertBatch.java, s\u00e5 finnes denne koden p\u00e5 GitHub. Du kan se spesifikt hvilke foresp\u00f8rslser som genereres der. Det er ikke viktig.<\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"PostgreSQL og JDBC \u2013 vi presser alt ut. Vladimir Sitnikov\" src=\"\/wp-content\/uploads\/2020\/05\/28dede211fe401286685ca62081453de.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>Vi har startet. Og det f\u00f8rste vi forstod er at uten batch \u2013 det er rett og slett umulig. Alle batch-alternativer er lik null, dvs. kj\u00f8retiden er praktisk talt lik null sammenlignet med en enkelt utf\u00f8relse. <\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"PostgreSQL og JDBC \u2013 vi presser alt ut. Vladimir Sitnikov\" src=\"\/wp-content\/uploads\/2020\/05\/4ea68f712bbdeadd35f5baa4ddaeff33.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>Vi setter inn data. Det er en ganske enkel tabell. Tre kolonner. Og hva ser vi her? Vi ser at alle disse tre alternativene er omtrent sammenlignbare. Og COPY er selvf\u00f8lgelig best.<\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"PostgreSQL og JDBC \u2013 vi presser alt ut. Vladimir Sitnikov\" src=\"\/wp-content\/uploads\/2020\/05\/2686f1d7eea347a839ac23aef2a27e53.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>Dette er n\u00e5r vi setter inn i biter. N\u00e5r vi sa ett VALUES-verdi, to VALUES-verdier, tre VALUES-verdier, eller vi oppga 10 med komma. Dette er akkurat n\u00e5 horisontalt. 1, 2, 4, 128. Det er tydelig at Batch Insert, som er tegnet med bl\u00e5tt, gj\u00f8r det mye lettere. Det vil si, n\u00e5r du setter inn \u00e9n om gangen eller til og med n\u00e5r du setter inn fire, s\u00e5 blir det dobbelt s\u00e5 bra, bare fordi vi klarte \u00e5 stappe litt mer inn i VALUES. F\u00e6rre EXECUTE-operasjoner.<\/p>\n<p><\/p>\n<p>\u00c5 bruke COPY p\u00e5 sm\u00e5 volum er ekstremt lite lovende. Jeg tegnet ikke engang de f\u00f8rste to. De g\u00e5r i skyene, dvs. disse gr\u00f8nne tallene for COPY.<\/p>\n<p><\/p>\n<p>COPY b\u00f8r brukes n\u00e5r du har datamengder som minimum er st\u00f8rre enn hundre rader. Overhead ved \u00e5 \u00e5pne denne forbindelsen er stor. Og, \u00e6rlig talt, jeg har ikke gravd i denne retningen. Jeg optimaliserte batchen, men COPY gjorde jeg ikke. <\/p>\n<p><\/p>\n<p>Hva gj\u00f8r vi videre? Vi har m\u00e5lt. Vi forst\u00e5r at vi m\u00e5 bruke enten strukturer eller det smart batching som kombinerer flere verdier. <\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"PostgreSQL og JDBC \u2013 vi presser alt ut. Vladimir Sitnikov\" src=\"\/wp-content\/uploads\/2020\/05\/e02fa2574e2d1b678382db15064610d3.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>Hva m\u00e5 vi ta med oss fra dagens foredrag?<\/p>\n<p><\/p>\n<ul>\n<li>PreparedStatement \u2013 det er v\u00e5rt alt. Det gir oss mye for ytelsen. Det gir oss en stor krukke med tj\u00e6re. <\/li>\n<li>Og vi m\u00e5 gj\u00f8re EXPLAIN ANALYZE 6 ganger.<\/li>\n<li>Og vi m\u00e5 blande inn OFFSET 0, og triks som +0 for \u00e5 rette opp den gjenv\u00e6rende prosentandelen av v\u00e5re problematiske sp\u00f8rringer.<\/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.5 - 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\/no\/blog\/administrirovanie\/postgresql-i-jdbc-vyzhimaem-vse-soki-vladimir-sitnikov\" \/>\n\t\t<meta name=\"generator\" content=\"All in One SEO (AIOSEO) 5.0.5\" \/>\n\t\t<meta property=\"og:locale\" content=\"nn_NO\" \/>\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\/no\/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 ut alt vi kan. Vladimir Sitnikov | ProHoster","description":"Jeg vil dele analysen av Vladimir Sitnikovs rapport fra begynnelsen av 2016 \"PostgreSQL og JDBC, vi presser ut alt vi kan\".","canonical_url":"https:\/\/prohoster.info\/no\/blog\/administrirovanie\/postgresql-i-jdbc-vyzhimaem-vse-soki-vladimir-sitnikov","robots":"max-image-preview:large","keywords":"","webmasterTools":{"miscellaneous":""},"schema":null,"og:locale":"nn_NO","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\/no\/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\/no\/wp-json\/wp\/v2\/posts\/79893","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/prohoster.info\/no\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/prohoster.info\/no\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/prohoster.info\/no\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/prohoster.info\/no\/wp-json\/wp\/v2\/comments?post=79893"}],"version-history":[{"count":0,"href":"https:\/\/prohoster.info\/no\/wp-json\/wp\/v2\/posts\/79893\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/prohoster.info\/no\/wp-json\/wp\/v2\/media\/79894"}],"wp:attachment":[{"href":"https:\/\/prohoster.info\/no\/wp-json\/wp\/v2\/media?parent=79893"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/prohoster.info\/no\/wp-json\/wp\/v2\/categories?post=79893"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/prohoster.info\/no\/wp-json\/wp\/v2\/tags?post=79893"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}