{"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\/sv\/blog\/administrirovanie\/postgresql-i-jdbc-vyzhimaem-vse-soki-vladimir-sitnikov","title":{"rendered":"PostgreSQL och JDBC: vi pressar ut det sista. Vladimir Sitnikov","gt_translate_keys":[{"key":"rendered","format":"text"}]},"content":{"rendered":"<p><strong>Jag f\u00f6resl\u00e5r att ni bekantar er med avskriften av Vladimir Sitnikovs f\u00f6redrag fr\u00e5n b\u00f6rjan av 2016, \"PostgreSQL och JDBC - vi pressar ut all saft\".<\/strong><\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"PostgreSQL och JDBC: vi pressar ut det sista. 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 och JDBC: vi pressar ut det sista. Vladimir Sitnikov\" src=\"\/wp-content\/uploads\/2020\/05\/030666abda53aa388b1cb1d0c46a7524.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>God dag! Jag heter Vladimir Sitnikov. Jag har arbetat i 10 \u00e5r p\u00e5 NetCracker. Jag fokuserar fr\u00e4mst p\u00e5 prestanda. Allt som har att g\u00f6ra med Java och SQL \u00e4r det jag brinner f\u00f6r. <\/p>\n<p><\/p>\n<p>Idag kommer jag att ber\u00e4tta om de utmaningar vi st\u00f6tt p\u00e5 n\u00e4r vi b\u00f6rjade anv\u00e4nda PostgreSQL som databasserver. Vi arbetar fr\u00e4mst med Java, men det jag kommer att tala om idag g\u00e4ller inte bara Java. Som erfarenhet visat sig, uppst\u00e5r detta \u00e4ven i andra spr\u00e5k. <\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"PostgreSQL och JDBC: vi pressar ut det sista. Vladimir Sitnikov\" src=\"\/wp-content\/uploads\/2020\/05\/b01a214d782c7e32797a6c6466457979.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>Vi kommer att tala om:<\/p>\n<p><\/p>\n<ul>\n<li>dataval. <\/li>\n<li>databevarande. <\/li>\n<li>och \u00e4ven prestanda. <\/li>\n<li>Och om de fallgropar som finns d\u00e4r. <\/li>\n<\/ul>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"PostgreSQL och JDBC: vi pressar ut det sista. Vladimir Sitnikov\" src=\"\/wp-content\/uploads\/2020\/05\/57da0c6aa4bb62e1beb77160f5aee7e7.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>L\u00e5t oss b\u00f6rja med en simpel fr\u00e5ga. Vi h\u00e4mtar en rad fr\u00e5n tabellen med hj\u00e4lp av det prim\u00e4ra nyckeln. <\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"PostgreSQL och JDBC: vi pressar ut det sista. Vladimir Sitnikov\" src=\"\/wp-content\/uploads\/2020\/05\/d5fcb1172aef402a87064498bf8a5218.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>Datan finns p\u00e5 samma v\u00e4rd. Och allt detta tar 20 millisekunder.<\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"PostgreSQL och JDBC: vi pressar ut det sista. Vladimir Sitnikov\" src=\"\/wp-content\/uploads\/2020\/05\/103b7f9736b82a3313491b2f0d2a5824.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>De 20 millisekunderna \u00e4r mycket. Om ni har 100 s\u00e5dana f\u00f6rfr\u00e5gningar, sl\u00f6sar ni tid i en sekund f\u00f6r att bearbeta dessa, det vill s\u00e4ga ni sl\u00f6sar tid.<\/p>\n<p><\/p>\n<p>Vi gillar inte att g\u00f6ra det och kollar vad databasen erbjuder f\u00f6r det. Den erbjuder oss tv\u00e5 alternativ f\u00f6r att k\u00f6ra f\u00f6rfr\u00e5gningar. <\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"PostgreSQL och JDBC: vi pressar ut det sista. Vladimir Sitnikov\" src=\"\/wp-content\/uploads\/2020\/05\/b467e86a0f8c4c32cea182fe27a28e6e.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>Det f\u00f6rsta alternativet \u00e4r en enkel f\u00f6rfr\u00e5gan. Vad \u00e4r bra med den? Jo, vi tar bara den och skickar den, och inget mer. <\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"PostgreSQL och JDBC: vi pressar ut det sista. 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 ocks\u00e5 en ut\u00f6kad f\u00f6rfr\u00e5gan, som \u00e4r mer komplicerad men ocks\u00e5 mer funktionell. Man kan skicka f\u00f6rfr\u00e5gningar f\u00f6r parsing, exekvering, bindning av variabler etc. separat. <\/p>\n<p><\/p>\n<p>Superut\u00f6kad f\u00f6rfr\u00e5gan \u2013 detta \u00e4r n\u00e5got vi inte kommer att t\u00e4cka i den aktuella presentationen. Kanske har vi n\u00e5gra \u00f6nskem\u00e5l fr\u00e5n databasen, och det finns en lista av \u00f6nskem\u00e5l som \u00e4r p\u00e5 n\u00e5got s\u00e4tt formulerad, allts\u00e5 det vi vill ha, men som f\u00f6r n\u00e4rvarande och under det n\u00e4rmaste \u00e5ret \u00e4r om\u00f6jligt. S\u00e5 vi har helt enkelt bara skrivit ner det och kommer att g\u00e5 och be grundl\u00e4ggande personer att ta en titt.<\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"PostgreSQL och JDBC: vi pressar ut det sista. Vladimir Sitnikov\" src=\"\/wp-content\/uploads\/2020\/05\/19094729074fd28c5b9f236833a9a266.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>S\u00e5 vad vi kan g\u00f6ra \u00e4r enkel f\u00f6rfr\u00e5gan och ut\u00f6kad f\u00f6rfr\u00e5gan.<\/p>\n<p><\/p>\n<p>Vad \u00e4r k\u00e4nnetecknet f\u00f6r varje metod? <\/p>\n<p><\/p>\n<p>En enkel f\u00f6rfr\u00e5gan \u00e4r bra att anv\u00e4nda f\u00f6r eng\u00e5ngsuppl\u00e4gg. Man utf\u00f6r den och gl\u00f6mmer den. Problemet \u00e4r att den inte st\u00f6der bin\u00e4rt dataformat, vilket inneb\u00e4r att den inte passar f\u00f6r vissa h\u00f6gpresterande system.<\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"PostgreSQL och JDBC: vi pressar ut det sista. Vladimir Sitnikov\" src=\"\/wp-content\/uploads\/2020\/05\/062c0e45cefd91ece331a306a7651bde.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>Utvidet sp\u00f8rring \u2013 lar deg spare tid p\u00e5 parsing. Dette er hva vi har gjort og begynt \u00e5 bruke. Det har v\u00e6rt ekstremt til stor hjelp for oss. Det er ikke bare besparelse p\u00e5 parsing. Det er ogs\u00e5 besparelser p\u00e5 dataoverf\u00f8ring. \u00c5 overf\u00f8re data i bin\u00e6rt format er mye mer effektivt. <\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"PostgreSQL och JDBC: vi pressar ut det sista. 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. Dette kan v\u00e6re Java osv. <\/p>\n<p><\/p>\n<p>Vi opprettet en statement. Utf\u00f8rte kommandoen. Opprettet close. Hvor ligger feilen her? Hva er problemet? Det er ingen problemer. S\u00e5nn st\u00e5r det skrevet i alle b\u00f8ker. Det m\u00e5 skrives slik. Hvis du vil ha maksimal ytelse, skriv s\u00e5nn. <\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"PostgreSQL och JDBC: vi pressar ut det sista. 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 fungerer. Hvorfor? Fordi vi har metoden \u00abclose\u00bb. Og n\u00e5r vi gj\u00f8r det p\u00e5 denne m\u00e5ten, blir det, sett fra databasen, som 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 lasting av statements? De er ingen til hjelp. Men vanligvis skjer det s\u00e5nn med PreparedStatement, n\u00e5r vi lukker dem, stenger de alt i databasen. Dette er ikke det vi vil. <\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"PostgreSQL och JDBC: vi pressar ut det sista. Vladimir Sitnikov\" src=\"\/wp-content\/uploads\/2020\/05\/5a357a209e414024c437d042f600f251.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>Vi vil, som friske mennesker, jobbe med databasen. F\u00f8rst forbereder vi statement v\u00e5rt once, deretter utf\u00f8rer vi det mange ganger. Egentlig mange ganger betyr \u00e9n gang i l\u00f8pet av applikasjonens liv. Og ved ulike REST bruker vi den samme statement ID-en. Dette er v\u00e5rt m\u00e5l. <\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"PostgreSQL och JDBC: vi pressar ut det sista. 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 och JDBC: vi pressar ut det sista. Vladimir Sitnikov\" src=\"\/wp-content\/uploads\/2020\/05\/0f101d890d1a2af8e99f8a3a8a06fd5a.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>Det er veldig enkelt \u2013 ikke lukk statements. Skriv slik: \u00abprepare\u00bb \u00abexecute\u00bb. <\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"PostgreSQL och JDBC: vi pressar ut det sista. 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 och JDBC: vi pressar ut det sista. 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 noe s\u00e5nt, vil det v\u00e6re klart at et eller annet vil g\u00e5 over styr et sted. Hvis det ikke er klart, kan vi m\u00e5le. La oss lage et benchmark hvor denne enkle metoden blir testet. Vi oppretter en statement. Kj\u00f8rer med en bestemt versjon av driveren og f\u00e5r vite at den faller ganske raskt med tap av all minnet som vi hadde. <\/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 t\u00e5pelig, men likevel. <\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"PostgreSQL och JDBC: vi pressar ut det sista. Vladimir Sitnikov\" src=\"\/wp-content\/uploads\/2020\/05\/b232a6205e708c70f52be0024bbe9980.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>Hvordan jobbe riktig? Hva m\u00e5 vi gj\u00f8re for dette?<\/p>\n<p><\/p>\n<p>I virkeligheten lukker applikasjoner alltid statements. I alle b\u00f8ker st\u00e5r det at de m\u00e5 lukkes, ellers vil minnet 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 vil heller ikke bruke tid p\u00e5 parsing. <\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"PostgreSQL och JDBC: vi pressar ut det sista. 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>Det f\u00f6rsta alternativet \u00e4r att vi s\u00e4ger att l\u00e5t oss sl\u00e5 in allt i PgSQL. D\u00e4r finns det cache. Den cachar allt. Det kommer att bli bra. Vi har sett p\u00e5 det. Vi har 100500 f\u00f6rfr\u00e5gningar. Det fungerar inte. Vi \u00e4r inte \u00f6verens \u2013 vi vill inte omvandla f\u00f6rfr\u00e5gningar till procedurer manuellt. Nej-nej. <\/p>\n<p><\/p>\n<p>Vi har ett andra alternativ \u2013 att sj\u00e4lva bygga det. Vi \u00f6ppnar k\u00e4llkoden, b\u00f6rjar bygga. Bygger och bygger. Det visade sig inte vara s\u00e5 sv\u00e5rt. <\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"PostgreSQL och JDBC: vi pressar ut det sista. 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>Detta d\u00f6k upp i augusti 2015. Nu finns det en mer modern version. Och allt \u00e4r bra. Det fungerar s\u00e5 bra att vi inte \u00e4ndrar n\u00e5got i applikationen. Och vi har till och med slutat t\u00e4nka i termer av PgSQL, det vill s\u00e4ga, detta var tillr\u00e4ckligt f\u00f6r att vi skulle kunna minska alla kostnader praktiskt taget till noll. <\/p>\n<p><\/p>\n<p>D\u00e4rf\u00f6r aktiveras Server-prepared statements vid den femte k\u00f6rningen f\u00f6r att inte sl\u00f6sa minne i databasen p\u00e5 varje eng\u00e5ngsf\u00f6rfr\u00e5gan. <\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"PostgreSQL och JDBC: vi pressar ut det sista. Vladimir Sitnikov\" src=\"\/wp-content\/uploads\/2020\/05\/8ee95e71f92187941989ad0c18ece0c0.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>Man kan fr\u00e5ga \u2013 var \u00e4r siffrorna? Vad f\u00e5r ni? Och h\u00e4r ger jag inga siffror, eftersom de varierar f\u00f6r varje f\u00f6rfr\u00e5gan.<\/p>\n<p><\/p>\n<p>Vi hade f\u00f6rfr\u00e5gningar d\u00e4r vi p\u00e5 OLTP-f\u00f6rfr\u00e5gningar spenderade cirka 20 millisekunder p\u00e5 parsing. Det var 0,5 millisekunder f\u00f6r k\u00f6rning, 20 millisekunder f\u00f6r parsing. F\u00f6rfr\u00e5gan \u2013 10 KiB text, 170 rader av planen. Det \u00e4r en OLTP-f\u00f6rfr\u00e5gan. Den fr\u00e5gar 1, 5, 10 rader, ibland fler. <\/p>\n<p><\/p>\n<p>Men vi ville absolut inte spendera 20 millisekunder. Vi fick det till 0. Allt \u00e4r bra. <\/p>\n<p><\/p>\n<p>Vad kan ni ta med er h\u00e4rifr\u00e5n? Om ni har Java, s\u00e5 tar ni den moderna versionen av drivrutinen och \u00e4r glada. <\/p>\n<p><\/p>\n<p>Om ni har n\u00e5got annat spr\u00e5k, s\u00e5 \u00f6verv\u00e4g \u2013 kanske detta ocks\u00e5 \u00e4r n\u00e5got ni beh\u00f6ver? F\u00f6r ur slutkundens synvinkel, till exempel, om ni har PL 8 eller LibPQ, s\u00e5 \u00e4r det inte uppenbart att ni sl\u00f6sar tid inte p\u00e5 k\u00f6rning, utan p\u00e5 parsing, och detta \u00e4r v\u00e4rt att kontrollera. Hur? Allt \u00e4r gratis. <\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"PostgreSQL och JDBC: vi pressar ut det sista. Vladimir Sitnikov\" src=\"\/wp-content\/uploads\/2020\/05\/fda6b1c1b126cb85c970e42335e1dc24.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>Med undantag f\u00f6r att det finns fel, vissa egenskaper. Och om dem ska vi just nu prata. St\u00f6rsta delen kommer att handla om industriell arkeologi, om vad vi har funnit, vad vi har st\u00f6tt p\u00e5. <\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"PostgreSQL och JDBC: vi pressar ut det sista. Vladimir Sitnikov\" src=\"\/wp-content\/uploads\/2020\/05\/9a3b383f83c5e227cd02952c5825b64f.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>Om f\u00f6rfr\u00e5gan genereras dynamiskt. S\u00e5nt h\u00e4nder. N\u00e5gon klipper ihop str\u00e4ngar, vilket ger en SQL-f\u00f6rfr\u00e5gan.<\/p>\n<p><\/p>\n<p>Vad \u00e4r d\u00e5 d\u00e5ligt med det? Det \u00e4r d\u00e5ligt p\u00e5 s\u00e5 s\u00e4tt att vi varje g\u00e5ng f\u00e5r en annan str\u00e4ng.<\/p>\n<p><\/p>\n<p>Och denna olika rad beh\u00f6ver r\u00e4kna hashCode igen. Det \u00e4r verkligen en CPU-uppgift \u2013 att hitta en l\u00e5ng f\u00f6rfr\u00e5gan i en redan befintlig hash \u00e4r inte s\u00e5 enkelt. S\u00e5 slutsatsen \u00e4r enkel \u2013 generera inte f\u00f6rfr\u00e5gningar. Lagra dem i en och samma variabel. Och var glad.<\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"PostgreSQL och JDBC: vi pressar ut det sista. Vladimir Sitnikov\" src=\"\/wp-content\/uploads\/2020\/05\/bcd4f729204cecdb572a98f357bcc33f.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>N\u00e4sta problem. Datatyper \u00e4r viktiga. Det finns ORM:er som s\u00e4ger att det inte spelar n\u00e5gon roll vilken NULL det \u00e4r, det kan vara vilken slags som helst. Om det \u00e4r Int, s\u00e5 s\u00e4ger vi setInt. Och om det \u00e4r NULL, l\u00e5t det alltid vara VARCHAR. Vad spelar det egentligen f\u00f6r roll vilken NULL som \u00e4r d\u00e4r? Databasen kommer att f\u00f6rst\u00e5 allt sj\u00e4lv. Och den bilden fungerar inte. <\/p>\n<p><\/p>\n<p>I praktiken bryr sig inte databasen det minsta. <strong>Om du f\u00f6rsta g\u00e5ngen sa att det h\u00e4r \u00e4r ett nummer, och andra g\u00e5ngen sa att det \u00e4r VARCHAR, d\u00e5 g\u00e5r det inte att \u00e5teranv\u00e4nda Server-prepared statements. I s\u00e5 fall m\u00e5ste vi \u00e5terskapa v\u00e5r statement.<\/strong><\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"PostgreSQL och JDBC: vi pressar ut det sista. Vladimir Sitnikov\" src=\"\/wp-content\/uploads\/2020\/05\/552d9c2e25cf9abbdfef12c98d027740.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>Om du k\u00f6r samma f\u00f6rfr\u00e5gan, se till att datatyperna i kolumnen inte blandas ihop. Det \u00e4r viktigt att h\u00e5lla koll p\u00e5 NULL. Det \u00e4r ett vanligt fel som vi hade efter att vi b\u00f6rjade anv\u00e4nda PreparedStatements.<\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"PostgreSQL och JDBC: vi pressar ut det sista. Vladimir Sitnikov\" src=\"\/wp-content\/uploads\/2020\/05\/5d73c8f5dfa281c3bda962fc3e5edd84.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>Bra, vi slog p\u00e5. Vi tog kanske en drivrutin. Och prestandan sj\u00f6nk. Allt blev d\u00e5ligt. <\/p>\n<p><\/p>\n<p>Hur kan det h\u00e4nda? \u00c4r det en bugg eller en funktion? Tyv\u00e4rr lyckades vi inte f\u00f6rst\u00e5 \u2013 \u00e4r det en bugg eller en funktion? Men det finns ett ganska enkelt s\u00e4tt att reproducera detta problem. Det \u00f6verraskade oss helt. Det handlar om att h\u00e4mta data fr\u00e5n bokstavligen en tabell. Vi hade f\u00f6rst\u00e5s fler s\u00e5dana f\u00f6rfr\u00e5gningar. De inkluderade vanligtvis tv\u00e5-tre tabeller, men det finns ett s\u00e5dant reproduktionsscenario. Ta vilken version som helst av din databas och upprepa.<\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"PostgreSQL och JDBC: vi pressar ut det sista. 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>Po\u00e4ngen \u00e4r att vi har tv\u00e5 kolumner, varav varje \u00e4r indexerad. I den ena kolumnen ligger en miljon rader med v\u00e4rdet NULL. I den andra kolumnen finns bara 20 rader. N\u00e4r vi k\u00f6r utan kopplade variabler fungerar allt bra. <\/p>\n<p><\/p>\n<p>Om vi b\u00f6rjar k\u00f6ra med kopplade variabler, det vill s\u00e4ga att vi anv\u00e4nder tecknet \u201e?\u201d eller \u201e$1\u201d f\u00f6r v\u00e5r f\u00f6rfr\u00e5gan, vad f\u00e5r vi d\u00e5?<\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"PostgreSQL och JDBC: vi pressar ut det sista. 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\u00f6rsta k\u00f6rningen \u2013 som vanligt. Andra \u2013 lite snabbare. N\u00e5got har cachats. Tredje-fj\u00e4rde-femte. Sedan pl\u00f6tsligt \u2013 och s\u00e5 h\u00e4r. Och det v\u00e4rsta \u00e4r att det h\u00e4nder vid sj\u00e4tte k\u00f6rningen. Vem visste att man beh\u00f6vde g\u00f6ra just sex k\u00f6rningar f\u00f6r att f\u00f6rst\u00e5 vilken plan som verkligen g\u00e4ller?<\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"PostgreSQL och JDBC: vi pressar ut det sista. Vladimir Sitnikov\" src=\"\/wp-content\/uploads\/2020\/05\/893c955bc1e2e15a6986690e516f72a9.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>Vem b\u00e4r ansvaret? Vad h\u00e4nde? Databasen inneh\u00e5ller optimering. Och den \u00e4r slags optimerad f\u00f6r det generiska fallet. Och d\u00e4rf\u00f6r, fr\u00e5n ett visst tillf\u00e4lle, \u00f6verg\u00e5r den till den generiska planen som tyv\u00e4rr kan vara en annan. Den kan vara densamma, men den kan ocks\u00e5 vara en annan. Och det finns ett tr\u00f6skelv\u00e4rde som leder till ett s\u00e5dant beteende. <\/p>\n<p><\/p>\n<p>Vad kan vi g\u00f6ra \u00e5t detta? H\u00e4r \u00e4r det n\u00e5got mer komplicerat att spekulera. Det finns en enkel l\u00f6sning som vi anv\u00e4nder. Det \u00e4r +0, OFFSET 0. Ni k\u00e4nner s\u00e4kert till s\u00e5dana l\u00f6sningar. Vi l\u00e4gger helt enkelt till \u00ab+0\u00bb i f\u00f6rfr\u00e5gan och allt \u00e4r bra. Jag visar det senare. <\/p>\n<p><\/p>\n<p>Och det finns ocks\u00e5 ett alternativ - att titta noggrannare p\u00e5 planerna. Utvecklaren m\u00e5ste inte bara skriva f\u00f6rfr\u00e5gan utan ocks\u00e5 s\u00e4ga \u00abexplain analyze\u00bb sex g\u00e5nger. Om det \u00e4r fem g\u00e5nger, s\u00e5 passar det inte. <\/p>\n<p><\/p>\n<p>Och det finns ocks\u00e5 det tredje alternativet - att skriva ett brev till pgsql-hackers. Jag har skrivit, men det \u00e4r fortfarande oklart - \u00e4r det en bugg eller en funktion?<\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"PostgreSQL och JDBC: vi pressar ut det sista. 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>Medan vi t\u00e4nker - \u00e4r det en bugg eller en funktion, l\u00e5t oss fixa det. Vi tar v\u00e5r f\u00f6rfr\u00e5gan och l\u00e4gger till \u00ab+0\u00bb. Allt \u00e4r bra. Tv\u00e5 tecken och man beh\u00f6ver inte ens t\u00e4nka p\u00e5 hur det g\u00e5r till. V\u00e4ldigt enkelt. Vi har helt enkelt f\u00f6rbjudit databasen fr\u00e5n att anv\u00e4nda indexet f\u00f6r den h\u00e4r kolumnen. Vi har inget index f\u00f6r kolumnen \u00ab+0\u00bb och allt, databasen anv\u00e4nder inte indexet, allt \u00e4r bra. <\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"PostgreSQL och JDBC: vi pressar ut det sista. Vladimir Sitnikov\" src=\"\/wp-content\/uploads\/2020\/05\/5261d80d084786a15b9764f6367014cd.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>Det h\u00e4r \u00e4r regeln f\u00f6r sex \u00abexplain\u00bb. Just nu i de aktuella versionerna m\u00e5ste man g\u00f6ra det sex g\u00e5nger om man har relaterade variabler. Om man inte har relaterade variabler g\u00f6r vi s\u00e5 h\u00e4r. Och vi f\u00e5r i slut\u00e4ndan just den h\u00e4r f\u00f6rfr\u00e5gan att falla. Det \u00e4r inte komplicerat.<\/p>\n<p><\/p>\n<p>Det verkar som om hur mycket kan man? H\u00e4r \u00e4r en bugg, d\u00e4r \u00e4r en bugg. Verkligen buggar \u00f6verallt. <\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"PostgreSQL och JDBC: vi pressar ut det sista. Vladimir Sitnikov\" src=\"\/wp-content\/uploads\/2020\/05\/674dc7e7b4624baa5c79eee9e1e89db0.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>L\u00e5t oss titta p\u00e5 en g\u00e5ng till. Till exempel, vi har tv\u00e5 scheman. Schema A med tabellen \u042b och schema B med tabellen \u042b. F\u00f6rfr\u00e5gan - att h\u00e4mta data fr\u00e5n tabellen. Vad kommer vi att f\u00e5? Vi kommer att f\u00e5 ett fel. Vi kommer att ha allt ovanst\u00e5ende. Regeln \u00e4r s\u00e5 h\u00e4r - bugg \u00f6verallt, vi kommer att ha allt ovanst\u00e5ende.<\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"PostgreSQL och JDBC: vi pressar ut det sista. Vladimir Sitnikov\" src=\"\/wp-content\/uploads\/2020\/05\/dd6f544bb9e930c39e36523c9afe6003.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>Nu fr\u00e5gan: \u00abVarf\u00f6r?\u00bb. Det verkar som om det finns dokumentation, att om vi har ett schema, s\u00e5 finns det variabeln \u00absearch_path\u00bb som s\u00e4ger var man ska leta efter tabellen. Det verkar som om variabeln finns.<\/p>\n<p><\/p>\n<p>Vad \u00e4r problemet? Problemet \u00e4r att serverberedda uttalanden inte misst\u00e4nker att n\u00e5gon kan \u00e4ndra \u00absearch_path\u00bb. Det h\u00e4r v\u00e4rdet f\u00f6rblir som en konstant f\u00f6r databasen. Och vissa delar kanske inte f\u00e5nga de nya v\u00e4rdena. <\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"PostgreSQL och JDBC: vi pressar ut det sista. Vladimir Sitnikov\" src=\"\/wp-content\/uploads\/2020\/05\/f738301606d84d72bfa7cc5b568c0df8.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>Sj\u00e4lvklart beror det p\u00e5 vilken version du testar. Det beror p\u00e5 hur mycket dina tabeller skiljer sig \u00e5t. Version 9.1 kommer helt enkelt att k\u00f6ra de gamla fr\u00e5gorna. Nyare versioner kan uppt\u00e4cka misstaget och s\u00e4ga att du har ett fel.<\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"PostgreSQL och JDBC: vi pressar ut det sista. 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-prepared statements =<br \/>\ncached plan m\u00e5ste inte \u00e4ndra resultattyp<\/a><\/noindex><\/p>\n<p><\/p>\n<p>Hur \u00e5tg\u00e4rdar man detta? Det finns ett enkelt recept \u2013 g\u00f6r inte s\u00e5. \u00c4ndra inte search_path i applikationens arbete. Om du \u00e4ndrar det \u00e4r det b\u00e4ttre att skapa en ny anslutning.<\/p>\n<p><\/p>\n<p>Vi kan diskutera det, det vill s\u00e4ga \u00f6ppna upp, diskutera, fylla p\u00e5. Kanske kan vi \u00f6vertyga databasutvecklarna om att n\u00e4r n\u00e5gon f\u00f6r\u00e4ndrar ett v\u00e4rde, b\u00f6r databasen informera klienten: 'Titta, det finns ett nytt v\u00e4rde h\u00e4r. Kanske beh\u00f6ver du \u00e5terst\u00e4lla statements, \u00e5terskapa dem?'. Just nu beter sig databasen p\u00e5 ett dolt s\u00e4tt och meddelar ingenting om att statements har f\u00f6r\u00e4ndrats n\u00e5gonstans inuti. <\/p>\n<p><\/p>\n<p>Och jag ska \u00e5terigen betona \u2013 detta \u00e4r inte typiskt f\u00f6r Java. Vi kommer att se samma sak i PL\/pgSQL direkt ett till ett. Men d\u00e4r kommer det att reproduceras.<\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"PostgreSQL och JDBC: vi pressar ut det sista. Vladimir Sitnikov\" src=\"\/wp-content\/uploads\/2020\/05\/a4e7b201d0c0aa4a0092d2b6ff152df7.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>L\u00e5t oss f\u00f6rs\u00f6ka h\u00e4mta data igen. Vi h\u00e4mtar och h\u00e4mtar. Vi har en tabell med en miljon rader. Varje rad \u00e4r ett kilobyte. Ungef\u00e4r en gigabyte data. Och vi har en arbetsminne i Java-maskinen p\u00e5 128 megabyte. <\/p>\n<p><\/p>\n<p>Vi, som rekommenderas i alla b\u00f6cker, anv\u00e4nder str\u00f6mmande behandling. Det vill s\u00e4ga, vi \u00f6ppnar resultSet och l\u00e4ser data d\u00e4rifr\u00e5n lite i taget. Kommer detta att fungera? Kommer det att krascha av minnesbrist? Kommer det att l\u00e4sa lite i taget? L\u00e5t oss ha tro p\u00e5 databasen, p\u00e5 Postgres. Vi tror inte. Ska vi f\u00e5 OutOfMemory? Vem har f\u00e5tt OutOfMemory? Och vem lyckades fixa det? N\u00e5gon lyckades reda ut det. <\/p>\n<p><\/p>\n<p>Om du har en miljon rader, kan du inte bara h\u00e4mta dem. Du m\u00e5ste definitivt anv\u00e4nda OFFSET\/LIMIT. Vem \u00e4r f\u00f6r det alternativet? Och vem tycker att man ska leka med autoCommit? <\/p>\n<p><\/p>\n<p>H\u00e4r visar det sig som vanligt att det ov\u00e4ntade alternativet \u00e4r det r\u00e4tta. Och om du pl\u00f6tsligt st\u00e4nger av autoCommit s\u00e5 hj\u00e4lper det. Varf\u00f6r \u00e4r det s\u00e5? Vetenskapen vet inte. <\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"PostgreSQL och JDBC: vi pressar ut det sista. 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 h\u00e4mtar alla klienter som ansluter till databasen Postgres all data. PgJDBC \u00e4r inget undantag, det h\u00e4mtar alla rader.<\/p>\n<p><\/p>\n<p>Det finns en variation p\u00e5 temat FetchSize, det vill s\u00e4ga man kan p\u00e5 niv\u00e5 med ett enskilt statement ange att h\u00e4r, sn\u00e4lla h\u00e4mta data i omg\u00e5ngar om 10, 50. Men det fungerar inte f\u00f6rr\u00e4n du st\u00e4nger av autoCommit. Har du st\u00e4ngt av autoCommit \u2013 b\u00f6rjar det fungera. <\/p>\n<p><\/p>\n<p>Men att g\u00e5 igenom koden och s\u00e4tta setFetchSize \u00f6verallt \u00e4r obekv\u00e4mt. D\u00e4rf\u00f6r har vi gjort en inst\u00e4llning som anger standardv\u00e4rdet f\u00f6r hela anslutningen.<\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"PostgreSQL och JDBC: vi pressar ut det sista. 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 har sagt detta. Vi har st\u00e4llt in parametern. Och vad har vi f\u00e5tt? Om vi v\u00e4ljer p\u00e5 l\u00e5ga niv\u00e5er, till exempel, om vi v\u00e4ljer 10 rader, har vi ganska stora overhead-kostnader. D\u00e4rf\u00f6r b\u00f6r detta v\u00e4rde s\u00e4ttas till cirka hundra. <\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"PostgreSQL och JDBC: vi pressar ut det sista. Vladimir Sitnikov\" src=\"\/wp-content\/uploads\/2020\/05\/073e7a4af63688396eefe332ba8261d6.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>Idealiskt sett, f\u00f6rst\u00e5s, kan vi \u00e4ven l\u00e4ra oss att begr\u00e4nsa i byte, men receptet \u00e4r f\u00f6ljande: s\u00e4tt defaultRowFetchSize \u00f6ver hundra och var glad. <\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"PostgreSQL och JDBC: vi pressar ut det sista. Vladimir Sitnikov\" src=\"\/wp-content\/uploads\/2020\/05\/e3078faf2078fcaec10d6d99872a9990.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>L\u00e5t oss g\u00e5 vidare till datains\u00e4ttning. Ins\u00e4ttning \u00e4r enklare, det finns olika alternativ. Till exempel, INSERT, VALUES. Det \u00e4r ett bra alternativ. Man kan s\u00e4ga \"INSERT SELECT\". I praktiken \u00e4r det samma sak. Det finns ingen skillnad i prestanda. <\/p>\n<p><\/p>\n<p>B\u00f6cker s\u00e4ger att man m\u00e5ste utf\u00f6ra Batch-statements, b\u00f6cker s\u00e4ger att man kan utf\u00f6ra mer komplexa kommandon med flera parenteser. Och i Postgres finns det en fantastisk funktion \u2013 man kan g\u00f6ra COPY, dvs. g\u00f6ra detta snabbare. <\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"PostgreSQL och JDBC: vi pressar ut det sista. Vladimir Sitnikov\" src=\"\/wp-content\/uploads\/2020\/05\/4d281c9515bdf8de7fbf1e9922d192d0.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>Om vi m\u00e4ter, kan vi \u00e5terigen g\u00f6ra flera intressanta uppt\u00e4ckter. Hur vill vi att detta ska fungera? Vi vill inte parsa och inte utf\u00f6ra on\u00f6diga kommandon. <\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"PostgreSQL och JDBC: vi pressar ut det sista. Vladimir Sitnikov\" src=\"\/wp-content\/uploads\/2020\/05\/7b2e4343c51dab3ddb6919bf0f117c4d.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>I praktiken till\u00e5ter TCP oss inte att g\u00f6ra s\u00e5. Om klienten \u00e4r upptagen med att skicka en f\u00f6rfr\u00e5gan, l\u00e4ser inte databasen f\u00f6rfr\u00e5gningarna n\u00e4r den f\u00f6rs\u00f6ker skicka tillbaka svaren. I slut\u00e4ndan v\u00e4ntar klienten p\u00e5 databasen medan den l\u00e4ser f\u00f6rfr\u00e5gan, och databasen v\u00e4ntar p\u00e5 klienten medan den l\u00e4ser svaret. <\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"PostgreSQL och JDBC: vi pressar ut det sista. Vladimir Sitnikov\" src=\"\/wp-content\/uploads\/2020\/05\/17a062c30ddd83cb890775ec1722044f.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>Och d\u00e4rf\u00f6r tvingas klienten periodiskt skicka en synkroniseringspaket. On\u00f6dig n\u00e4tverksinteraktion, on\u00f6dig tidsf\u00f6rlust.<\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"PostgreSQL och JDBC: vi pressar ut det sista. Vladimir Sitnikov\" src=\"\/wp-content\/uploads\/2020\/05\/ae7a4f32e2949c1d0550da051937de02.jpg\" style=\"display:block;margin: 0 auto;\" \/>Och ju fler vi l\u00e4gger till, desto s\u00e4mre blir det. Drivern \u00e4r ganska pessimistisk och l\u00e4gger till dem ganska ofta, ungef\u00e4r var 200:e rad, beroende p\u00e5 radens storlek osv. <\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"PostgreSQL och JDBC: vi pressar ut det sista. 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>Det h\u00e4nder att om du bara \u00e4ndrar en rad s\u00e5 \u00f6kar allt med tio g\u00e5nger. S\u00e5dana saker h\u00e4nder. Varf\u00f6r? Som vanligt var en konstant n\u00e5gonstans redan anv\u00e4nd. Och v\u00e4rdet \"128\" innebar \u2013 att inte anv\u00e4nda batching.<\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"PostgreSQL och JDBC: vi pressar ut det sista. 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 \u00e4r bra att detta inte kom med i den officiella versionen. Vi uppt\u00e4ckte det innan vi b\u00f6rjade sl\u00e4ppa en version. Alla v\u00e4rden jag n\u00e4mner baseras p\u00e5 moderna versioner. <\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"PostgreSQL och JDBC: vi pressar ut det sista. Vladimir Sitnikov\" src=\"\/wp-content\/uploads\/2020\/05\/28c82d9e11f6bdaf3cf62b49fc074d68.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>L\u00e5t oss m\u00e4ta. Vi m\u00e4ter enkel InsertBatch. Vi m\u00e4ter multipel InsertBatch, dvs. samma sak, men med m\u00e5nga values. En smart strategi. Inte alla kan g\u00f6ra det, men det \u00e4r en enkel strategi, mycket enklare \u00e4n COPY.<\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"PostgreSQL och JDBC: vi pressar ut det sista. 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\u00f6ra COPY.<\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"PostgreSQL och JDBC: vi pressar ut det sista. Vladimir Sitnikov\" src=\"\/wp-content\/uploads\/2020\/05\/2b0d8bbcc50f1293c9a8a1eb8eb70d2e.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>Och detta kan g\u00f6ras med strukturer. Deklarera User standardtyp, \u00f6verf\u00f6r en array och s\u00e4tt in direkt i tabellen. <\/p>\n<p><\/p>\n<p>Om du \u00f6ppnar l\u00e4nken: pgjdbc\/ubenchmsrk\/InsertBatch.java, s\u00e5 finns denna kod p\u00e5 GitHub. Du kan se specifikt vilka fr\u00e5gor som genereras d\u00e4r. Det \u00e4r inte det viktiga.<\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"PostgreSQL och JDBC: vi pressar ut det sista. Vladimir Sitnikov\" src=\"\/wp-content\/uploads\/2020\/05\/28dede211fe401286685ca62081453de.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>Vi har startat. Och det f\u00f6rsta vi ins\u00e5g \u00e4r att det \u00e4r helt om\u00f6jligt att inte anv\u00e4nda batch \u2013 alla alternativ till batching \u00e4r likv\u00e4rdiga med noll, det vill s\u00e4ga k\u00f6rningstiden \u00e4r praktiskt taget noll j\u00e4mf\u00f6rt med att k\u00f6ra en g\u00e5ng. <\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"PostgreSQL och JDBC: vi pressar ut det sista. Vladimir Sitnikov\" src=\"\/wp-content\/uploads\/2020\/05\/4ea68f712bbdeadd35f5baa4ddaeff33.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>Vi s\u00e4tter in data. Det \u00e4r en ganska enkel tabell. Tre kolumner. Och vad ser vi h\u00e4r? Vi ser att alla dessa tre alternativ \u00e4r ungef\u00e4r j\u00e4mf\u00f6rbara. Och COPY \u00e4r sj\u00e4lvklart b\u00e4ttre.<\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"PostgreSQL och JDBC: vi pressar ut det sista. Vladimir Sitnikov\" src=\"\/wp-content\/uploads\/2020\/05\/2686f1d7eea347a839ac23aef2a27e53.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>Det \u00e4r n\u00e4r vi s\u00e4tter in bit f\u00f6r bit. N\u00e4r vi sa att ett v\u00e4rde VALUES, tv\u00e5 v\u00e4rden VALUES, tre v\u00e4rden VALUES eller vi angav dem d\u00e4r 10 med kommatecken. Det \u00e4r just nu \u00e5t sidan. 1, 2, 4, 128. Det \u00e4r tydligt att Batch Insert, som \u00e4r ritat i bl\u00e5tt, l\u00e4ttas av detta. Det vill s\u00e4ga, n\u00e4r du s\u00e4tter in en och en, eller till och med n\u00e4r du s\u00e4tter in fyra, s\u00e5 blir det i tv\u00e5 g\u00e5nger b\u00e4ttre, bara f\u00f6r att vi tryckte lite mer i VALUES. F\u00e4rre EXECUTE-operationer.<\/p>\n<p><\/p>\n<p>Att anv\u00e4nda COPY f\u00f6r sm\u00e5 volymer \u00e4r extremt orealistiskt. Jag ritade inte ens p\u00e5 de tv\u00e5 f\u00f6rsta. De g\u00e5r till himlen, det vill s\u00e4ga dessa gr\u00f6na siffror f\u00f6r COPY.<\/p>\n<p><\/p>\n<p>COPY b\u00f6r anv\u00e4ndas n\u00e4r du har \u00e5tminstone mer \u00e4n hundra rader. \u00d6verheaden f\u00f6r att \u00f6ppna denna anslutning \u00e4r stor. Och, \u00e4rligt talat, har jag inte gr\u00e4vt i den riktningen. Jag har optimerat batch, COPY \u2013 nej. <\/p>\n<p><\/p>\n<p>Vad g\u00f6r vi h\u00e4rn\u00e4st? Vi har m\u00e4tt. Vi f\u00f6rst\u00e5r att vi b\u00f6r anv\u00e4nda antingen strukturer eller en smart batch som kombinerar flera v\u00e4rden. <\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"PostgreSQL och JDBC: vi pressar ut det sista. Vladimir Sitnikov\" src=\"\/wp-content\/uploads\/2020\/05\/e02fa2574e2d1b678382db15064610d3.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>Vad m\u00e5ste vi ta med oss fr\u00e5n dagens f\u00f6rel\u00e4sning?<\/p>\n<p><\/p>\n<ul>\n<li>PreparedStatement \u2013 detta \u00e4r allt f\u00f6r oss. Det ger mycket f\u00f6r prestanda. Det ger en stor spann med tj\u00e4ra. <\/li>\n<li>Och vi m\u00e5ste g\u00f6ra EXPLAIN ANALYZE 6 g\u00e5nger.<\/li>\n<li>Och vi m\u00e5ste sp\u00e4da ut OFFSET 0, och trick som +0 f\u00f6r att r\u00e4tta till den kvarvarande procenten av v\u00e5ra problematiska fr\u00e5gor.<\/li>\n<\/ul>\n<p>K\u00e4lla: <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.4 - 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\/sv\/blog\/administrirovanie\/postgresql-i-jdbc-vyzhimaem-vse-soki-vladimir-sitnikov\" \/>\n\t\t<meta name=\"generator\" content=\"All in One SEO (AIOSEO) 5.0.4\" \/>\n\t\t<meta property=\"og:locale\" content=\"sv_SE\" \/>\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\/sv\/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 och JDBC pressar vi ut alla saft. Vladimir Sitnikov | ProHoster","description":"Jag f\u00f6resl\u00e5r att ni bekantar er med transkriptet av Vladimir Sitnikovs presentation fr\u00e5n b\u00f6rjan av 2016, \"PostgreSQL och JDBC: Utnyttja all potential\"","canonical_url":"https:\/\/prohoster.info\/sv\/blog\/administrirovanie\/postgresql-i-jdbc-vyzhimaem-vse-soki-vladimir-sitnikov","robots":"max-image-preview:large","keywords":"","webmasterTools":{"miscellaneous":""},"schema":null,"og:locale":"sv_SE","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\/sv\/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\/sv\/wp-json\/wp\/v2\/posts\/79893","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/prohoster.info\/sv\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/prohoster.info\/sv\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/prohoster.info\/sv\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/prohoster.info\/sv\/wp-json\/wp\/v2\/comments?post=79893"}],"version-history":[{"count":0,"href":"https:\/\/prohoster.info\/sv\/wp-json\/wp\/v2\/posts\/79893\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/prohoster.info\/sv\/wp-json\/wp\/v2\/media\/79894"}],"wp:attachment":[{"href":"https:\/\/prohoster.info\/sv\/wp-json\/wp\/v2\/media?parent=79893"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/prohoster.info\/sv\/wp-json\/wp\/v2\/categories?post=79893"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/prohoster.info\/sv\/wp-json\/wp\/v2\/tags?post=79893"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}